@nalvietnam/avatar-cli 1.11.2 → 1.12.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
@@ -145,8 +145,8 @@ async function writeUserConfig(config) {
145
145
  }
146
146
  async function clearUserConfig() {
147
147
  if (await pathExists(USER_CONFIG_PATH)) {
148
- const { promises: fs14 } = await import("fs");
149
- await fs14.unlink(USER_CONFIG_PATH);
148
+ const { promises: fs15 } = await import("fs");
149
+ await fs15.unlink(USER_CONFIG_PATH);
150
150
  }
151
151
  }
152
152
  function isTokenExpired(config) {
@@ -2329,7 +2329,7 @@ function registerGitnexusCommand(program2) {
2329
2329
  }
2330
2330
 
2331
2331
  // src/commands/init.ts
2332
- import { select as select12 } from "@inquirer/prompts";
2332
+ import { select as select13 } from "@inquirer/prompts";
2333
2333
 
2334
2334
  // src/lib/avatar-ascii-banner.ts
2335
2335
  import chalk2 from "chalk";
@@ -2393,11 +2393,178 @@ ${renderAvatarBanner(opts)}
2393
2393
  }
2394
2394
 
2395
2395
  // src/lib/handle-remote-access-failure-with-account-switch.ts
2396
+ import { spawnSync as spawnSync16 } from "child_process";
2397
+ import { input as input4, select as select6 } from "@inquirer/prompts";
2398
+
2399
+ // src/lib/reset-folder-git-and-create-new-remote-under-current-user.ts
2400
+ import { spawnSync as spawnSync14 } from "child_process";
2401
+ import { promises as fs9 } from "fs";
2402
+ import { basename, join as join16 } from "path";
2403
+ import { confirm as confirm4, select as select5 } from "@inquirer/prompts";
2404
+
2405
+ // src/lib/execute-gh-repo-create.ts
2406
+ import { spawnSync as spawnSync12 } from "child_process";
2407
+ var RepoAlreadyExistsError = class extends Error {
2408
+ constructor(fullName) {
2409
+ super(`Repo "${fullName}" \u0111\xE3 t\u1ED3n t\u1EA1i tr\xEAn GitHub. \u0110\u1ED5i t\xEAn ho\u1EB7c x\xF3a repo c\u0169.`);
2410
+ this.name = "RepoAlreadyExistsError";
2411
+ }
2412
+ };
2413
+ function executeGhRepoCreate(input8) {
2414
+ const fullName = `${input8.org}/${input8.name}`;
2415
+ const args = [
2416
+ "repo",
2417
+ "create",
2418
+ fullName,
2419
+ `--${input8.visibility}`,
2420
+ "--source",
2421
+ input8.folder,
2422
+ "--remote",
2423
+ "origin",
2424
+ "--push"
2425
+ ];
2426
+ const r = spawnSync12("gh", args, { stdio: "inherit" });
2427
+ if (r.status !== 0) {
2428
+ if (r.status === 1) {
2429
+ throw new RepoAlreadyExistsError(fullName);
2430
+ }
2431
+ throw new Error(`gh repo create th\u1EA5t b\u1EA1i (exit ${r.status})`);
2432
+ }
2433
+ return {
2434
+ sshUrl: `git@github.com:${fullName}.git`,
2435
+ httpsUrl: `https://github.com/${fullName}.git`
2436
+ };
2437
+ }
2438
+
2439
+ // src/lib/resolve-github-username-default.ts
2396
2440
  import { spawnSync as spawnSync13 } from "child_process";
2397
- import { input as input4, select as select5 } from "@inquirer/prompts";
2441
+ function resolveGithubUsernameDefault() {
2442
+ const r = spawnSync13("gh", ["api", "user", "--jq", ".login"], {
2443
+ encoding: "utf8",
2444
+ stdio: ["ignore", "pipe", "pipe"]
2445
+ });
2446
+ if (r.status !== 0) {
2447
+ throw new Error(`Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c GitHub username: ${r.stderr?.trim()}`);
2448
+ }
2449
+ return r.stdout.trim();
2450
+ }
2451
+
2452
+ // src/lib/validate-repo-name-and-visibility.ts
2453
+ var REPO_NAME_REGEX = /^[a-zA-Z0-9._-]{1,100}$/;
2454
+ var InvalidRepoNameError = class extends Error {
2455
+ constructor(name) {
2456
+ super(
2457
+ `T\xEAn repo "${name}" kh\xF4ng h\u1EE3p l\u1EC7. Ch\u1EC9 d\xF9ng ch\u1EEF/s\u1ED1/d\u1EA5u ch\u1EA5m/g\u1EA1ch/underscore, d\xE0i 1-100 k\xFD t\u1EF1.`
2458
+ );
2459
+ this.name = "InvalidRepoNameError";
2460
+ }
2461
+ };
2462
+ function validateRepoName(name) {
2463
+ if (!REPO_NAME_REGEX.test(name)) {
2464
+ throw new InvalidRepoNameError(name);
2465
+ }
2466
+ }
2467
+ function validateRepoVisibility(v) {
2468
+ if (v !== "private" && v !== "public") {
2469
+ throw new Error(`Visibility ph\u1EA3i l\xE0 "private" ho\u1EB7c "public", nh\u1EADn: "${v}"`);
2470
+ }
2471
+ }
2472
+
2473
+ // src/lib/create-github-remote-from-folder.ts
2474
+ function createGithubRemoteFromFolder(input8) {
2475
+ validateRepoName(input8.name);
2476
+ validateRepoVisibility(input8.visibility);
2477
+ const org = input8.org ?? resolveGithubUsernameDefault();
2478
+ log.info(`T\u1EA1o GitHub repo ${org}/${input8.name} (${input8.visibility})...`);
2479
+ const urls = executeGhRepoCreate({
2480
+ folder: input8.folder,
2481
+ org,
2482
+ name: input8.name,
2483
+ visibility: input8.visibility
2484
+ });
2485
+ log.success(`\u0110\xE3 t\u1EA1o: ${urls.sshUrl}`);
2486
+ return urls;
2487
+ }
2488
+
2489
+ // src/lib/reset-folder-git-and-create-new-remote-under-current-user.ts
2490
+ function backupTimestamp() {
2491
+ const d = /* @__PURE__ */ new Date();
2492
+ return `${d.getFullYear().toString().slice(-2)}${String(d.getMonth() + 1).padStart(2, "0")}${String(d.getDate()).padStart(2, "0")}-${String(d.getHours()).padStart(2, "0")}${String(d.getMinutes()).padStart(2, "0")}`;
2493
+ }
2494
+ async function backupExistingDotGit(folderPath) {
2495
+ const gitDir = join16(folderPath, ".git");
2496
+ if (!await pathExists(gitDir)) {
2497
+ throw new Error(`.git kh\xF4ng t\u1ED3n t\u1EA1i \u1EDF ${folderPath} \u2014 kh\xF4ng c\u1EA7n reset.`);
2498
+ }
2499
+ const backupName = `.git.backup-${backupTimestamp()}`;
2500
+ const backupPath = join16(folderPath, backupName);
2501
+ await fs9.rename(gitDir, backupPath);
2502
+ log.success(`Backup .git \u2192 ${backupName}`);
2503
+ return backupPath;
2504
+ }
2505
+ function reinitGitInFolder(folderPath) {
2506
+ const r1 = spawnSync14("git", ["-C", folderPath, "init", "-b", "main"], {
2507
+ encoding: "utf8",
2508
+ stdio: ["ignore", "pipe", "pipe"]
2509
+ });
2510
+ if (r1.status !== 0) {
2511
+ throw new Error(`git init th\u1EA5t b\u1EA1i: ${r1.stderr || r1.stdout}`);
2512
+ }
2513
+ log.success("Git init m\u1EDBi (branch main)");
2514
+ spawnSync14("git", ["-C", folderPath, "add", "-A"], {
2515
+ encoding: "utf8",
2516
+ stdio: ["ignore", "pipe", "pipe"]
2517
+ });
2518
+ const r3 = spawnSync14(
2519
+ "git",
2520
+ ["-C", folderPath, "commit", "-m", "chore: initial commit from existing folder"],
2521
+ { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
2522
+ );
2523
+ if (r3.status !== 0) {
2524
+ log.warn(`git commit th\u1EA5t b\u1EA1i (folder c\xF3 th\u1EC3 r\u1ED7ng): ${(r3.stderr || "").slice(0, 200)}`);
2525
+ } else {
2526
+ log.success("Initial commit");
2527
+ }
2528
+ }
2529
+ async function resetFolderGitAndCreateNewRemoteUnderCurrentUser(opts) {
2530
+ const folderName = basename(opts.folderPath);
2531
+ const repoName = opts.repoName ?? folderName;
2532
+ if (!opts.autoYes) {
2533
+ const confirmed = await confirm4({
2534
+ message: `Folder '${folderName}' s\u1EBD \u0111\u01B0\u1EE3c reset:
2535
+ 1. Backup .git \u2192 .git.backup-{timestamp}
2536
+ 2. Git init m\u1EDBi (branch main, initial commit)
2537
+ 3. T\u1EA1o GitHub repo m\u1EDBi '${repoName}' d\u01B0\u1EDBi account c\u1EE7a b\u1EA1n
2538
+ Ti\u1EBFp t\u1EE5c?`,
2539
+ default: true
2540
+ });
2541
+ if (!confirmed) {
2542
+ throw new Error("User abort reset folder.");
2543
+ }
2544
+ }
2545
+ const visibility = opts.visibility ?? (opts.autoYes ? "private" : await select5({
2546
+ message: "Visibility cho repo m\u1EDBi?",
2547
+ choices: [
2548
+ { name: "private (m\u1EB7c \u0111\u1ECBnh)", value: "private" },
2549
+ { name: "public", value: "public" }
2550
+ ]
2551
+ }));
2552
+ const backupPath = await backupExistingDotGit(opts.folderPath);
2553
+ reinitGitInFolder(opts.folderPath);
2554
+ const urls = createGithubRemoteFromFolder({
2555
+ folder: opts.folderPath,
2556
+ name: repoName,
2557
+ visibility,
2558
+ org: opts.org
2559
+ });
2560
+ return {
2561
+ newRemoteUrl: urls.httpsUrl,
2562
+ backupPath
2563
+ };
2564
+ }
2398
2565
 
2399
2566
  // src/lib/verify-git-remote-accessible.ts
2400
- import { spawnSync as spawnSync12 } from "child_process";
2567
+ import { spawnSync as spawnSync15 } from "child_process";
2401
2568
  var TIMEOUT_MS = 5e3;
2402
2569
  function classifyRemoteError(stderr) {
2403
2570
  const text = stderr.toLowerCase();
@@ -2413,7 +2580,7 @@ function classifyRemoteError(stderr) {
2413
2580
  return "unknown";
2414
2581
  }
2415
2582
  function tryVerifyGitRemoteAccessible(url) {
2416
- const r = spawnSync12("git", ["ls-remote", "--exit-code", url, "HEAD"], {
2583
+ const r = spawnSync15("git", ["ls-remote", "--exit-code", url, "HEAD"], {
2417
2584
  encoding: "utf8",
2418
2585
  timeout: TIMEOUT_MS,
2419
2586
  stdio: ["ignore", "pipe", "pipe"]
@@ -2435,7 +2602,7 @@ var RemoteAccessAbortedError = class extends Error {
2435
2602
  }
2436
2603
  };
2437
2604
  function getCurrentGhUser() {
2438
- const r = spawnSync13("gh", ["api", "user", "--jq", ".login"], {
2605
+ const r = spawnSync16("gh", ["api", "user", "--jq", ".login"], {
2439
2606
  encoding: "utf8",
2440
2607
  stdio: ["ignore", "pipe", "pipe"]
2441
2608
  });
@@ -2444,7 +2611,7 @@ function getCurrentGhUser() {
2444
2611
  }
2445
2612
  function triggerGhAuthLoginInteractive() {
2446
2613
  log.info("M\u1EDF browser \u0111\u1EC3 switch GitHub account...");
2447
- const r = spawnSync13("gh", ["auth", "login", "--web"], { stdio: "inherit" });
2614
+ const r = spawnSync16("gh", ["auth", "login", "--web"], { stdio: "inherit" });
2448
2615
  if (r.status !== 0) {
2449
2616
  log.warn(`gh auth login exit ${r.status}. B\u1EA1n c\xF3 th\u1EC3 ch\u1EA1y tay r\u1ED3i quay l\u1EA1i retry.`);
2450
2617
  }
@@ -2478,32 +2645,54 @@ async function handleRemoteAccessFailureWithAccountSwitch(args) {
2478
2645
  log.dim(` L\xFD do: ${reason}${detail ? ` \u2014 ${detail.slice(0, 150)}` : ""}`);
2479
2646
  log.info(getReasonHint(reason, currentUrl, ghUser));
2480
2647
  if (ghUser) log.dim(` gh CLI hi\u1EC7n \u0111ang login: ${ghUser}`);
2481
- const action = await select5({
2482
- message: "C\xE1ch x\u1EED l\xFD?",
2483
- choices: [
2484
- {
2485
- name: "Nh\u1EADp l\u1EA1i URL \u0111\xFAng (recommended khi URL sai ch\xEDnh t\u1EA3)",
2486
- value: "re-input-url"
2487
- },
2488
- {
2489
- name: "Switch GitHub account (gh auth login \u2014 m\u1EDF browser)",
2490
- value: "switch"
2491
- },
2492
- {
2493
- name: "T\xF4i v\u1EEBa fix (accept invite / s\u1EEDa permission) \u2014 retry verify",
2494
- value: "retry"
2495
- },
2496
- {
2497
- name: "T\u1EA1m ng\u01B0ng init \u2014 ch\u1EA1y l\u1EA1i 'avatar init' sau",
2498
- value: "abort"
2499
- }
2500
- ]
2648
+ const choices = [
2649
+ {
2650
+ name: "Nh\u1EADp l\u1EA1i URL \u0111\xFAng (recommended khi URL sai ch\xEDnh t\u1EA3)",
2651
+ value: "re-input-url"
2652
+ },
2653
+ {
2654
+ name: "Switch GitHub account (gh auth login \u2014 m\u1EDF browser)",
2655
+ value: "switch"
2656
+ },
2657
+ {
2658
+ name: "T\xF4i v\u1EEBa fix (accept invite / s\u1EEDa permission) \u2014 retry verify",
2659
+ value: "retry"
2660
+ }
2661
+ ];
2662
+ if (args.folderPath) {
2663
+ choices.push({
2664
+ name: "Reset folder & t\u1EA1o repo M\u1EDAI d\u01B0\u1EDBi account c\u1EE7a t\xF4i (backup .git c\u0169)",
2665
+ value: "reset-folder"
2666
+ });
2667
+ }
2668
+ choices.push({
2669
+ name: "T\u1EA1m ng\u01B0ng init \u2014 ch\u1EA1y l\u1EA1i 'avatar init' sau",
2670
+ value: "abort"
2501
2671
  });
2672
+ const action = await select6({ message: "C\xE1ch x\u1EED l\xFD?", choices });
2502
2673
  if (action === "abort") {
2503
2674
  throw new RemoteAccessAbortedError(
2504
2675
  `User ch\u1ECDn t\u1EA1m ng\u01B0ng. Fix access ${currentUrl} r\u1ED3i ch\u1EA1y l\u1EA1i 'avatar init'.`
2505
2676
  );
2506
2677
  }
2678
+ if (action === "reset-folder") {
2679
+ if (!args.folderPath) {
2680
+ log.warn("Reset folder c\u1EA7n folderPath \u2014 internal error.");
2681
+ continue;
2682
+ }
2683
+ try {
2684
+ const reset = await resetFolderGitAndCreateNewRemoteUnderCurrentUser({
2685
+ folderPath: args.folderPath,
2686
+ visibility: args.defaultVisibility
2687
+ });
2688
+ log.success(`Folder \u0111\xE3 reset. Backup t\u1EA1i: ${reset.backupPath}`);
2689
+ log.success(`Remote m\u1EDBi: ${reset.newRemoteUrl}`);
2690
+ return { resolvedUrl: reset.newRemoteUrl };
2691
+ } catch (err) {
2692
+ log.warn(`Reset folder th\u1EA5t b\u1EA1i: ${err.message}`);
2693
+ continue;
2694
+ }
2695
+ }
2507
2696
  if (action === "re-input-url") {
2508
2697
  const newUrl = await input4({
2509
2698
  message: "URL git remote (https://github.com/owner/repo.git ho\u1EB7c git@github.com:owner/repo.git):",
@@ -2528,14 +2717,14 @@ async function handleRemoteAccessFailureWithAccountSwitch(args) {
2528
2717
 
2529
2718
  // src/lib/safe-bootstrap-for-dirty-folder.ts
2530
2719
  import { readdirSync } from "fs";
2531
- import { select as select6 } from "@inquirer/prompts";
2720
+ import { select as select7 } from "@inquirer/prompts";
2532
2721
  import { simpleGit as simpleGit3 } from "simple-git";
2533
2722
 
2534
2723
  // src/lib/check-folder-has-git.ts
2535
2724
  import { existsSync as existsSync6, statSync } from "fs";
2536
- import { join as join16 } from "path";
2725
+ import { join as join17 } from "path";
2537
2726
  function checkFolderHasGit(folderPath) {
2538
- const gitPath = join16(folderPath, ".git");
2727
+ const gitPath = join17(folderPath, ".git");
2539
2728
  if (!existsSync6(gitPath)) return false;
2540
2729
  const stat = statSync(gitPath);
2541
2730
  return stat.isDirectory() || stat.isFile();
@@ -2567,7 +2756,7 @@ async function createInitialGitCommit(folderPath) {
2567
2756
 
2568
2757
  // src/lib/detect-folder-tech-stack.ts
2569
2758
  import { existsSync as existsSync7 } from "fs";
2570
- import { join as join17 } from "path";
2759
+ import { join as join18 } from "path";
2571
2760
  var SIGNATURES = {
2572
2761
  node: ["package.json"],
2573
2762
  python: ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile"],
@@ -2579,7 +2768,7 @@ var SIGNATURES = {
2579
2768
  function detectFolderTechStack(folderPath) {
2580
2769
  const matched = [];
2581
2770
  for (const [stack, files] of Object.entries(SIGNATURES)) {
2582
- if (files.some((f) => existsSync7(join17(folderPath, f)))) {
2771
+ if (files.some((f) => existsSync7(join18(folderPath, f)))) {
2583
2772
  matched.push(stack);
2584
2773
  }
2585
2774
  }
@@ -2588,25 +2777,25 @@ function detectFolderTechStack(folderPath) {
2588
2777
 
2589
2778
  // src/lib/gitignore-template-loader.ts
2590
2779
  import { readFileSync as readFileSync3 } from "fs";
2591
- import { dirname as dirname4, join as join18 } from "path";
2780
+ import { dirname as dirname4, join as join19 } from "path";
2592
2781
  import { fileURLToPath as fileURLToPath2 } from "url";
2593
2782
  var __dirname = dirname4(fileURLToPath2(import.meta.url));
2594
2783
  var CANDIDATE_DIRS = [
2595
2784
  // Bundled production: dist/index.js → __dirname = .../dist/, sibling dist/templates
2596
- join18(__dirname, "templates", "gitignore"),
2785
+ join19(__dirname, "templates", "gitignore"),
2597
2786
  // Legacy bundled: nếu file là dist/lib/*.js (sub-bundle), templates ở dist/templates
2598
- join18(__dirname, "..", "templates", "gitignore"),
2787
+ join19(__dirname, "..", "templates", "gitignore"),
2599
2788
  // Dev mode (vitest/tsx run src/ trực tiếp): __dirname = src/lib/
2600
- join18(__dirname, "..", "..", "src", "templates", "gitignore"),
2789
+ join19(__dirname, "..", "..", "src", "templates", "gitignore"),
2601
2790
  // npm-installed alt: __dirname = .../dist/ → package_root/src/templates
2602
- join18(__dirname, "..", "src", "templates", "gitignore")
2791
+ join19(__dirname, "..", "src", "templates", "gitignore")
2603
2792
  ];
2604
2793
  var AVATAR_MARKER_START = "# === avatar ===";
2605
2794
  var AVATAR_MARKER_END = "# === /avatar ===";
2606
2795
  function readTemplate(stack) {
2607
2796
  for (const dir of CANDIDATE_DIRS) {
2608
2797
  try {
2609
- return readFileSync3(join18(dir, `${stack}.txt`), "utf8");
2798
+ return readFileSync3(join19(dir, `${stack}.txt`), "utf8");
2610
2799
  } catch {
2611
2800
  }
2612
2801
  }
@@ -2621,9 +2810,9 @@ ${readTemplate(s).trim()}`);
2621
2810
 
2622
2811
  // src/lib/write-or-merge-gitignore.ts
2623
2812
  import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync } from "fs";
2624
- import { join as join19 } from "path";
2813
+ import { join as join20 } from "path";
2625
2814
  function writeOrMergeGitignore(folderPath, avatarBlock) {
2626
- const path = join19(folderPath, ".gitignore");
2815
+ const path = join20(folderPath, ".gitignore");
2627
2816
  if (!existsSync8(path)) {
2628
2817
  writeFileSync(path, avatarBlock, "utf8");
2629
2818
  return;
@@ -2665,7 +2854,7 @@ async function promptBootstrapStrategy(state, opts) {
2665
2854
  if (opts.presetStrategy) return opts.presetStrategy;
2666
2855
  if (opts.autoYes) return "stash";
2667
2856
  if (state === "empty" || state === "clean") return "commit-all";
2668
- return await select6({
2857
+ return await select7({
2669
2858
  message: state === "dirty" ? "Folder c\xF3 changes ch\u01B0a commit. C\xE1ch x\u1EED l\xFD:" : "Folder c\xF3 file ch\u01B0a version. C\xE1ch x\u1EED l\xFD:",
2670
2859
  choices: [
2671
2860
  {
@@ -2799,22 +2988,22 @@ async function safeBootstrapGitInFolder(folderPath, opts = {}) {
2799
2988
  }
2800
2989
 
2801
2990
  // src/lib/team-pack-submodule-manager.ts
2802
- import { join as join20 } from "path";
2991
+ import { join as join21 } from "path";
2803
2992
 
2804
2993
  // src/lib/check-team-pack-access-with-retry-loop.ts
2805
- import { spawnSync as spawnSync14 } from "child_process";
2806
- import { confirm as confirm4, select as select7 } from "@inquirer/prompts";
2994
+ import { spawnSync as spawnSync17 } from "child_process";
2995
+ import { confirm as confirm5, select as select8 } from "@inquirer/prompts";
2807
2996
  import boxen3 from "boxen";
2808
2997
  function parseRepoSlugFromGitUrl(url) {
2809
2998
  const httpsMatch = url.match(/github\.com[/:]([^/]+\/[^/]+?)(?:\.git)?$/);
2810
2999
  return httpsMatch?.[1] ?? null;
2811
3000
  }
2812
3001
  function checkRepoAccess(repoSlug) {
2813
- const r = spawnSync14("gh", ["api", `repos/${repoSlug}`], { stdio: "ignore" });
3002
+ const r = spawnSync17("gh", ["api", `repos/${repoSlug}`], { stdio: "ignore" });
2814
3003
  return r.status === 0;
2815
3004
  }
2816
3005
  function getCurrentGhUser2() {
2817
- const r = spawnSync14("gh", ["api", "user", "--jq", ".login"], {
3006
+ const r = spawnSync17("gh", ["api", "user", "--jq", ".login"], {
2818
3007
  encoding: "utf8",
2819
3008
  stdio: ["ignore", "pipe", "pipe"]
2820
3009
  });
@@ -2823,13 +3012,13 @@ function getCurrentGhUser2() {
2823
3012
  }
2824
3013
  function triggerGhAuthLoginInteractive2() {
2825
3014
  log.info("M\u1EDF browser \u0111\u1EC3 switch GitHub account...");
2826
- const r = spawnSync14("gh", ["auth", "login", "--web"], { stdio: "inherit" });
3015
+ const r = spawnSync17("gh", ["auth", "login", "--web"], { stdio: "inherit" });
2827
3016
  if (r.status !== 0) {
2828
3017
  log.warn(`gh auth login exit ${r.status}. C\xF3 th\u1EC3 ch\u1EA1y tay r\u1ED3i quay l\u1EA1i retry.`);
2829
3018
  }
2830
3019
  }
2831
3020
  async function copyInfoToClipboardWithConsent(info) {
2832
- const ok = await confirm4({
3021
+ const ok = await confirm5({
2833
3022
  message: "Copy th\xF4ng tin (GitHub username + email) v\xE0o clipboard \u0111\u1EC3 d\xE1n v\xE0o Slack/email?",
2834
3023
  default: true
2835
3024
  });
@@ -2881,7 +3070,7 @@ async function ensureTeamPackAccessWithRetry(args) {
2881
3070
  while (true) {
2882
3071
  const ghUser = getCurrentGhUser2();
2883
3072
  const ghUserDisplay = ghUser ?? "(ch\u01B0a gh auth)";
2884
- const action = await select7({
3073
+ const action = await select8({
2885
3074
  message: "C\xE1ch x\u1EED l\xFD?",
2886
3075
  choices: [
2887
3076
  {
@@ -2995,7 +3184,7 @@ async function addTeamPackSubmodule(projectRoot, tag, ssoEmail, latest = false)
2995
3184
  await checkoutBranchHeadInSubmodule(TEAM_PACK_RELATIVE_PATH, DEFAULT_PACK_BRANCH, projectRoot);
2996
3185
  return { pinnedTag: `${DEFAULT_PACK_BRANCH} (HEAD)` };
2997
3186
  }
2998
- const submoduleDir = join20(projectRoot, TEAM_PACK_RELATIVE_PATH);
3187
+ const submoduleDir = join21(projectRoot, TEAM_PACK_RELATIVE_PATH);
2999
3188
  const allTags = await listTags(submoduleDir);
3000
3189
  const target = pickLatestStableSemVerTag(allTags);
3001
3190
  if (target) {
@@ -3004,7 +3193,7 @@ async function addTeamPackSubmodule(projectRoot, tag, ssoEmail, latest = false)
3004
3193
  return { pinnedTag: target };
3005
3194
  }
3006
3195
  async function readPinnedPackVersion(projectRoot) {
3007
- const submoduleRoot = join20(projectRoot, TEAM_PACK_RELATIVE_PATH);
3196
+ const submoduleRoot = join21(projectRoot, TEAM_PACK_RELATIVE_PATH);
3008
3197
  const tag = await tagAtHead(submoduleRoot);
3009
3198
  if (tag) return tag;
3010
3199
  const sha = await currentCommitSha(submoduleRoot);
@@ -3012,97 +3201,13 @@ async function readPinnedPackVersion(projectRoot) {
3012
3201
  }
3013
3202
 
3014
3203
  // src/commands/init-flow-handlers-for-each-project-status.ts
3015
- import { basename as basename2, join as join26, resolve as resolve2 } from "path";
3016
- import { input as input7, select as select11 } from "@inquirer/prompts";
3017
-
3018
- // src/lib/execute-gh-repo-create.ts
3019
- import { spawnSync as spawnSync15 } from "child_process";
3020
- var RepoAlreadyExistsError = class extends Error {
3021
- constructor(fullName) {
3022
- super(`Repo "${fullName}" \u0111\xE3 t\u1ED3n t\u1EA1i tr\xEAn GitHub. \u0110\u1ED5i t\xEAn ho\u1EB7c x\xF3a repo c\u0169.`);
3023
- this.name = "RepoAlreadyExistsError";
3024
- }
3025
- };
3026
- function executeGhRepoCreate(input8) {
3027
- const fullName = `${input8.org}/${input8.name}`;
3028
- const args = [
3029
- "repo",
3030
- "create",
3031
- fullName,
3032
- `--${input8.visibility}`,
3033
- "--source",
3034
- input8.folder,
3035
- "--remote",
3036
- "origin",
3037
- "--push"
3038
- ];
3039
- const r = spawnSync15("gh", args, { stdio: "inherit" });
3040
- if (r.status !== 0) {
3041
- if (r.status === 1) {
3042
- throw new RepoAlreadyExistsError(fullName);
3043
- }
3044
- throw new Error(`gh repo create th\u1EA5t b\u1EA1i (exit ${r.status})`);
3045
- }
3046
- return {
3047
- sshUrl: `git@github.com:${fullName}.git`,
3048
- httpsUrl: `https://github.com/${fullName}.git`
3049
- };
3050
- }
3051
-
3052
- // src/lib/resolve-github-username-default.ts
3053
- import { spawnSync as spawnSync16 } from "child_process";
3054
- function resolveGithubUsernameDefault() {
3055
- const r = spawnSync16("gh", ["api", "user", "--jq", ".login"], {
3056
- encoding: "utf8",
3057
- stdio: ["ignore", "pipe", "pipe"]
3058
- });
3059
- if (r.status !== 0) {
3060
- throw new Error(`Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c GitHub username: ${r.stderr?.trim()}`);
3061
- }
3062
- return r.stdout.trim();
3063
- }
3064
-
3065
- // src/lib/validate-repo-name-and-visibility.ts
3066
- var REPO_NAME_REGEX = /^[a-zA-Z0-9._-]{1,100}$/;
3067
- var InvalidRepoNameError = class extends Error {
3068
- constructor(name) {
3069
- super(
3070
- `T\xEAn repo "${name}" kh\xF4ng h\u1EE3p l\u1EC7. Ch\u1EC9 d\xF9ng ch\u1EEF/s\u1ED1/d\u1EA5u ch\u1EA5m/g\u1EA1ch/underscore, d\xE0i 1-100 k\xFD t\u1EF1.`
3071
- );
3072
- this.name = "InvalidRepoNameError";
3073
- }
3074
- };
3075
- function validateRepoName(name) {
3076
- if (!REPO_NAME_REGEX.test(name)) {
3077
- throw new InvalidRepoNameError(name);
3078
- }
3079
- }
3080
- function validateRepoVisibility(v) {
3081
- if (v !== "private" && v !== "public") {
3082
- throw new Error(`Visibility ph\u1EA3i l\xE0 "private" ho\u1EB7c "public", nh\u1EADn: "${v}"`);
3083
- }
3084
- }
3085
-
3086
- // src/lib/create-github-remote-from-folder.ts
3087
- function createGithubRemoteFromFolder(input8) {
3088
- validateRepoName(input8.name);
3089
- validateRepoVisibility(input8.visibility);
3090
- const org = input8.org ?? resolveGithubUsernameDefault();
3091
- log.info(`T\u1EA1o GitHub repo ${org}/${input8.name} (${input8.visibility})...`);
3092
- const urls = executeGhRepoCreate({
3093
- folder: input8.folder,
3094
- org,
3095
- name: input8.name,
3096
- visibility: input8.visibility
3097
- });
3098
- log.success(`\u0110\xE3 t\u1EA1o: ${urls.sshUrl}`);
3099
- return urls;
3100
- }
3204
+ import { basename as basename3, join as join27, resolve as resolve2 } from "path";
3205
+ import { input as input7, select as select12 } from "@inquirer/prompts";
3101
3206
 
3102
3207
  // src/lib/check-gh-cli-auth-status.ts
3103
- import { spawnSync as spawnSync17 } from "child_process";
3208
+ import { spawnSync as spawnSync18 } from "child_process";
3104
3209
  function checkGhCliAuthStatus() {
3105
- const r = spawnSync17("gh", ["auth", "status"], { stdio: "ignore" });
3210
+ const r = spawnSync18("gh", ["auth", "status"], { stdio: "ignore" });
3106
3211
  if (r.error && r.error.code === "ENOENT") {
3107
3212
  return "not-installed";
3108
3213
  }
@@ -3110,12 +3215,12 @@ function checkGhCliAuthStatus() {
3110
3215
  }
3111
3216
 
3112
3217
  // src/lib/detect-package-manager.ts
3113
- import { spawnSync as spawnSync18 } from "child_process";
3218
+ import { spawnSync as spawnSync19 } from "child_process";
3114
3219
  function hasBinary(name) {
3115
3220
  const platform2 = detectHostPlatform();
3116
3221
  const probe = platform2 === "win32" ? "where" : "command";
3117
3222
  const args = platform2 === "win32" ? [name] : ["-v", name];
3118
- const r = spawnSync18(probe, args, {
3223
+ const r = spawnSync19(probe, args, {
3119
3224
  shell: platform2 !== "win32",
3120
3225
  stdio: "ignore"
3121
3226
  });
@@ -3131,7 +3236,7 @@ function detectPackageManager() {
3131
3236
  }
3132
3237
 
3133
3238
  // src/lib/install-gh-cli-via-package-manager.ts
3134
- import { spawnSync as spawnSync19 } from "child_process";
3239
+ import { spawnSync as spawnSync20 } from "child_process";
3135
3240
  var INSTALL_COMMANDS = {
3136
3241
  brew: { cmd: "brew", args: ["install", "gh"] },
3137
3242
  apt: { cmd: "sudo", args: ["apt-get", "install", "-y", "gh"] },
@@ -3142,7 +3247,7 @@ var INSTALL_COMMANDS = {
3142
3247
  function installGhCliViaPackageManager(pm) {
3143
3248
  const spec = INSTALL_COMMANDS[pm];
3144
3249
  log.info(`\u0110ang c\xE0i gh CLI qua ${pm}...`);
3145
- const r = spawnSync19(spec.cmd, spec.args, { stdio: "inherit" });
3250
+ const r = spawnSync20(spec.cmd, spec.args, { stdio: "inherit" });
3146
3251
  if (r.status !== 0) {
3147
3252
  throw new Error(`C\xE0i gh CLI th\u1EA5t b\u1EA1i qua ${pm} (exit ${r.status}). C\xE0i tay r\u1ED3i ch\u1EA1y l\u1EA1i.`);
3148
3253
  }
@@ -3150,9 +3255,9 @@ function installGhCliViaPackageManager(pm) {
3150
3255
  }
3151
3256
 
3152
3257
  // src/lib/setup-git-credential-via-gh.ts
3153
- import { spawnSync as spawnSync20 } from "child_process";
3258
+ import { spawnSync as spawnSync21 } from "child_process";
3154
3259
  function setupGitCredentialViaGh() {
3155
- const r = spawnSync20("gh", ["auth", "setup-git"], { stdio: "ignore" });
3260
+ const r = spawnSync21("gh", ["auth", "setup-git"], { stdio: "ignore" });
3156
3261
  if (r.status !== 0) {
3157
3262
  log.warn("gh auth setup-git fail (non-fatal). N\u1EBFu git clone l\u1ED7i 128 \u2192 ch\u1EA1y th\u1EE7 c\xF4ng.");
3158
3263
  return;
@@ -3161,10 +3266,10 @@ function setupGitCredentialViaGh() {
3161
3266
  }
3162
3267
 
3163
3268
  // src/lib/trigger-gh-cli-auth-login.ts
3164
- import { spawnSync as spawnSync21 } from "child_process";
3269
+ import { spawnSync as spawnSync22 } from "child_process";
3165
3270
  function triggerGhCliAuthLogin() {
3166
3271
  log.info("Kh\u1EDFi \u0111\u1ED9ng \u0111\u0103ng nh\u1EADp GitHub qua gh CLI (browser s\u1EBD m\u1EDF)...");
3167
- const r = spawnSync21(
3272
+ const r = spawnSync22(
3168
3273
  "gh",
3169
3274
  ["auth", "login", "--hostname", "github.com", "--web", "--git-protocol", "ssh"],
3170
3275
  { stdio: "inherit" }
@@ -3253,28 +3358,28 @@ async function ensureGitHubReady(remoteUrl) {
3253
3358
  }
3254
3359
 
3255
3360
  // src/lib/add-team-pack-submodule-with-retry-on-network-fail.ts
3256
- import { spawnSync as spawnSync22 } from "child_process";
3257
- import { select as select8 } from "@inquirer/prompts";
3361
+ import { spawnSync as spawnSync23 } from "child_process";
3362
+ import { select as select9 } from "@inquirer/prompts";
3258
3363
  function isSshPermissionError(message) {
3259
3364
  const text = message.toLowerCase();
3260
3365
  return text.includes("permission denied (publickey)") || text.includes("publickey)") || text.includes("ssh: could not resolve") || text.includes("host key verification failed");
3261
3366
  }
3262
3367
  function triggerGhAuthLoginInteractive3() {
3263
3368
  log.info("M\u1EDF browser \u0111\u1EC3 switch GitHub account...");
3264
- const r = spawnSync22("gh", ["auth", "login", "--web"], { stdio: "inherit" });
3369
+ const r = spawnSync23("gh", ["auth", "login", "--web"], { stdio: "inherit" });
3265
3370
  if (r.status !== 0) {
3266
3371
  log.warn(`gh auth login exit ${r.status}. C\xF3 th\u1EC3 ch\u1EA1y tay r\u1ED3i quay l\u1EA1i retry.`);
3267
3372
  }
3268
3373
  }
3269
3374
  function openGithubSshKeysPage() {
3270
3375
  log.info("M\u1EDF trang GitHub Settings \u2192 SSH Keys...");
3271
- const r = spawnSync22("open", ["https://github.com/settings/keys"], { stdio: "ignore" });
3376
+ const r = spawnSync23("open", ["https://github.com/settings/keys"], { stdio: "ignore" });
3272
3377
  if (r.status !== 0) {
3273
3378
  log.info("URL: https://github.com/settings/keys");
3274
3379
  }
3275
3380
  }
3276
3381
  async function handleSshPermissionError() {
3277
- return await select8({
3382
+ return await select9({
3278
3383
  message: "SSH permission denied. C\xE1ch x\u1EED l\xFD?",
3279
3384
  choices: [
3280
3385
  {
@@ -3448,12 +3553,12 @@ function parseBootstrapStrategyOpts(opts) {
3448
3553
  }
3449
3554
 
3450
3555
  // src/commands/workspace-scaffold-and-finalize-orchestrator.ts
3451
- import { join as join25 } from "path";
3452
- import { basename } from "path";
3453
- import { confirm as confirm5, input as input6, select as select10 } from "@inquirer/prompts";
3556
+ import { join as join26 } from "path";
3557
+ import { basename as basename2 } from "path";
3558
+ import { confirm as confirm6, input as input6, select as select11 } from "@inquirer/prompts";
3454
3559
 
3455
3560
  // src/lib/create-workspace-remote-via-gh.ts
3456
- import { spawnSync as spawnSync23 } from "child_process";
3561
+ import { spawnSync as spawnSync24 } from "child_process";
3457
3562
  var CreateWorkspaceRemoteError = class extends Error {
3458
3563
  reason;
3459
3564
  fullName;
@@ -3483,20 +3588,20 @@ function classifyGhCreateError(stderr) {
3483
3588
  return "unknown";
3484
3589
  }
3485
3590
  function repoExistsOnGitHub(fullName) {
3486
- const r = spawnSync23("gh", ["repo", "view", fullName, "--json", "name"], {
3591
+ const r = spawnSync24("gh", ["repo", "view", fullName, "--json", "name"], {
3487
3592
  stdio: "ignore"
3488
3593
  });
3489
3594
  return r.status === 0;
3490
3595
  }
3491
3596
  function canCreateInNamespace(org, ghUser) {
3492
3597
  if (org.toLowerCase() === ghUser.toLowerCase()) return { ok: true };
3493
- const r = spawnSync23("gh", ["api", `orgs/${org}/members/${ghUser}`, "--silent"], {
3598
+ const r = spawnSync24("gh", ["api", `orgs/${org}/members/${ghUser}`, "--silent"], {
3494
3599
  stdio: "ignore"
3495
3600
  });
3496
3601
  if (r.status === 0) return { ok: true };
3497
- const orgCheck = spawnSync23("gh", ["api", `orgs/${org}`, "--silent"], { stdio: "ignore" });
3602
+ const orgCheck = spawnSync24("gh", ["api", `orgs/${org}`, "--silent"], { stdio: "ignore" });
3498
3603
  if (orgCheck.status !== 0) {
3499
- const userCheck = spawnSync23("gh", ["api", `users/${org}`, "--silent"], { stdio: "ignore" });
3604
+ const userCheck = spawnSync24("gh", ["api", `users/${org}`, "--silent"], { stdio: "ignore" });
3500
3605
  if (userCheck.status === 0) {
3501
3606
  return {
3502
3607
  ok: false,
@@ -3532,7 +3637,7 @@ async function createWorkspaceRemoteViaGh(input8) {
3532
3637
  );
3533
3638
  }
3534
3639
  log.info(`T\u1EA1o GitHub repo cho workspace: ${fullName} (${input8.visibility})...`);
3535
- const r = spawnSync23(
3640
+ const r = spawnSync24(
3536
3641
  "gh",
3537
3642
  [
3538
3643
  "repo",
@@ -3573,7 +3678,7 @@ ${combined}
3573
3678
  function linkExistingRemoteToWorkspace(args) {
3574
3679
  const sshUrl = `git@github.com:${args.fullName}.git`;
3575
3680
  const httpsUrl = `https://github.com/${args.fullName}.git`;
3576
- const addResult = spawnSync23(
3681
+ const addResult = spawnSync24(
3577
3682
  "git",
3578
3683
  ["-C", args.workspacePath, "remote", "add", "origin", sshUrl],
3579
3684
  {
@@ -3582,7 +3687,7 @@ function linkExistingRemoteToWorkspace(args) {
3582
3687
  }
3583
3688
  );
3584
3689
  if (addResult.status !== 0) {
3585
- spawnSync23("git", ["-C", args.workspacePath, "remote", "set-url", "origin", sshUrl], {
3690
+ spawnSync24("git", ["-C", args.workspacePath, "remote", "set-url", "origin", sshUrl], {
3586
3691
  stdio: "ignore"
3587
3692
  });
3588
3693
  }
@@ -3591,8 +3696,8 @@ function linkExistingRemoteToWorkspace(args) {
3591
3696
  }
3592
3697
 
3593
3698
  // src/lib/merge-pack-settings-into-project-settings.ts
3594
- import { promises as fs9 } from "fs";
3595
- import { join as join21 } from "path";
3699
+ import { promises as fs10 } from "fs";
3700
+ import { join as join22 } from "path";
3596
3701
  async function isStatusLineCommandResolvable(workspacePath, command) {
3597
3702
  const trimmed = command.trim();
3598
3703
  const match = trimmed.match(/^(node|python|python3|bash|sh)\s+([^\s]+)/);
@@ -3600,7 +3705,7 @@ async function isStatusLineCommandResolvable(workspacePath, command) {
3600
3705
  return true;
3601
3706
  }
3602
3707
  const filePath = match[2];
3603
- const fullPath = filePath.startsWith("/") ? filePath : join21(workspacePath, filePath);
3708
+ const fullPath = filePath.startsWith("/") ? filePath : join22(workspacePath, filePath);
3604
3709
  return await pathExists(fullPath);
3605
3710
  }
3606
3711
  function backupFilename(originalPath) {
@@ -3634,8 +3739,8 @@ function mergeHooksPerEvent(packHooks, userHooks) {
3634
3739
  return { merged, touchedEvents: touched };
3635
3740
  }
3636
3741
  async function mergePackSettingsIntoProjectSettings(workspacePath) {
3637
- const packTemplatePath = join21(workspacePath, ".claude", "pack", "templates", "settings.json.tpl");
3638
- const projectSettingsPath = join21(workspacePath, ".claude", "settings.json");
3742
+ const packTemplatePath = join22(workspacePath, ".claude", "pack", "templates", "settings.json.tpl");
3743
+ const projectSettingsPath = join22(workspacePath, ".claude", "settings.json");
3639
3744
  if (!await pathExists(packTemplatePath)) {
3640
3745
  return { action: "no-pack-template", changes: [] };
3641
3746
  }
@@ -3729,18 +3834,18 @@ async function mergePackSettingsIntoProjectSettings(workspacePath) {
3729
3834
  let backupPath;
3730
3835
  if (projectHasSettings) {
3731
3836
  backupPath = backupFilename(projectSettingsPath);
3732
- await fs9.copyFile(projectSettingsPath, backupPath);
3837
+ await fs10.copyFile(projectSettingsPath, backupPath);
3733
3838
  }
3734
3839
  await writeJsonAtomic(projectSettingsPath, merged);
3735
3840
  return { action: "merged", backupPath, changes };
3736
3841
  }
3737
3842
 
3738
3843
  // src/lib/symlink-farm-for-team-pack-mount-dirs.ts
3739
- import { promises as fs11 } from "fs";
3740
- import { dirname as dirname6, join as join22, relative as relative2 } from "path";
3844
+ import { promises as fs12 } from "fs";
3845
+ import { dirname as dirname6, join as join23, relative as relative2 } from "path";
3741
3846
 
3742
3847
  // src/lib/backup-existing-dir-before-symlink-override.ts
3743
- import { promises as fs10 } from "fs";
3848
+ import { promises as fs11 } from "fs";
3744
3849
  function timestamp() {
3745
3850
  const d = /* @__PURE__ */ new Date();
3746
3851
  const pad = (n) => n.toString().padStart(2, "0");
@@ -3748,7 +3853,7 @@ function timestamp() {
3748
3853
  }
3749
3854
  async function backupDirBeforeReplace(targetPath) {
3750
3855
  const backupPath = `${targetPath}.backup-${timestamp()}`;
3751
- await fs10.rename(targetPath, backupPath);
3856
+ await fs11.rename(targetPath, backupPath);
3752
3857
  return backupPath;
3753
3858
  }
3754
3859
 
@@ -3764,7 +3869,7 @@ var TEAM_PACK_MOUNT_DIRS = [
3764
3869
  ];
3765
3870
  async function isSymbolicLink(path) {
3766
3871
  try {
3767
- const st = await fs11.lstat(path);
3872
+ const st = await fs12.lstat(path);
3768
3873
  return st.isSymbolicLink();
3769
3874
  } catch {
3770
3875
  return false;
@@ -3777,33 +3882,33 @@ async function syncMountedDir(source, dest, force) {
3777
3882
  }
3778
3883
  if (await pathExists(dest)) {
3779
3884
  if (await isSymbolicLink(dest)) {
3780
- await fs11.unlink(dest);
3885
+ await fs12.unlink(dest);
3781
3886
  } else if (force) {
3782
3887
  const backupPath = await backupDirBeforeReplace(dest);
3783
3888
  const relativeSource2 = relative2(dirname6(dest), source);
3784
- await fs11.symlink(relativeSource2, dest);
3889
+ await fs12.symlink(relativeSource2, dest);
3785
3890
  return { dir, action: "backed-up-and-linked", backupPath };
3786
3891
  } else {
3787
3892
  return { dir, action: "skipped-conflict" };
3788
3893
  }
3789
3894
  }
3790
3895
  const relativeSource = relative2(dirname6(dest), source);
3791
- await fs11.symlink(relativeSource, dest);
3896
+ await fs12.symlink(relativeSource, dest);
3792
3897
  return { dir, action: "created" };
3793
3898
  }
3794
3899
  async function syncAllMountDirs(packDir, claudeDir, force) {
3795
3900
  const results = [];
3796
3901
  for (const dir of TEAM_PACK_MOUNT_DIRS) {
3797
- const source = join22(packDir, dir);
3798
- const dest = join22(claudeDir, dir);
3902
+ const source = join23(packDir, dir);
3903
+ const dest = join23(claudeDir, dir);
3799
3904
  results.push(await syncMountedDir(source, dest, force));
3800
3905
  }
3801
3906
  return results;
3802
3907
  }
3803
3908
 
3804
3909
  // src/commands/init-success-rendering-and-helpers.ts
3805
- import { join as join24, relative as relative3 } from "path";
3806
- import { input as input5, select as select9 } from "@inquirer/prompts";
3910
+ import { join as join25, relative as relative3 } from "path";
3911
+ import { input as input5, select as select10 } from "@inquirer/prompts";
3807
3912
  import boxen5 from "boxen";
3808
3913
 
3809
3914
  // src/lib/format-pack-commands-cheatsheet-box.ts
@@ -3844,7 +3949,7 @@ function formatPackCommandsCheatsheetBox() {
3844
3949
 
3845
3950
  // src/commands/init-conflict-detection-helpers.ts
3846
3951
  import { readdir } from "fs/promises";
3847
- import { join as join23 } from "path";
3952
+ import { join as join24 } from "path";
3848
3953
  async function isEmptyOrMissing(path) {
3849
3954
  if (!await pathExists(path)) return true;
3850
3955
  try {
@@ -3857,7 +3962,7 @@ async function isEmptyOrMissing(path) {
3857
3962
  }
3858
3963
  async function findAlternativeWorkspaceName(parent, desiredName, maxAttempts = 10) {
3859
3964
  for (let i = 2; i < maxAttempts; i++) {
3860
- const candidate = join23(parent, `${desiredName}-${i}`);
3965
+ const candidate = join24(parent, `${desiredName}-${i}`);
3861
3966
  if (await isEmptyOrMissing(candidate)) return candidate;
3862
3967
  }
3863
3968
  return null;
@@ -3865,7 +3970,7 @@ async function findAlternativeWorkspaceName(parent, desiredName, maxAttempts = 1
3865
3970
 
3866
3971
  // src/commands/init-success-rendering-and-helpers.ts
3867
3972
  async function resolveWorkspacePath(parent, desiredName, force) {
3868
- const desired = join24(parent, desiredName);
3973
+ const desired = join25(parent, desiredName);
3869
3974
  if (await isEmptyOrMissing(desired)) return desired;
3870
3975
  log.warn(`Workspace path "${desired}" \u0111\xE3 c\xF3 n\u1ED9i dung.`);
3871
3976
  while (true) {
@@ -3880,7 +3985,7 @@ async function resolveWorkspacePath(parent, desiredName, force) {
3880
3985
  }
3881
3986
  choices.push({ name: "Nh\u1EADp t\xEAn workspace kh\xE1c (manual)", value: "manual" });
3882
3987
  choices.push({ name: "T\u1EA1m ng\u01B0ng init", value: "abort" });
3883
- const action = await select9({
3988
+ const action = await select10({
3884
3989
  message: "C\xE1ch x\u1EED l\xFD workspace path conflict?",
3885
3990
  choices
3886
3991
  });
@@ -3896,7 +4001,7 @@ async function resolveWorkspacePath(parent, desiredName, force) {
3896
4001
  message: "T\xEAn workspace m\u1EDBi:",
3897
4002
  validate: (v) => v.trim().length > 0 ? true : "T\xEAn kh\xF4ng \u0111\u01B0\u1EE3c r\u1ED7ng"
3898
4003
  });
3899
- const newPath = join24(parent, newName.trim());
4004
+ const newPath = join25(parent, newName.trim());
3900
4005
  if (await isEmptyOrMissing(newPath)) return newPath;
3901
4006
  log.warn(`"${newPath}" c\u0169ng \u0111\xE3 c\xF3 n\u1ED9i dung. Th\u1EED t\xEAn kh\xE1c.`);
3902
4007
  }
@@ -3953,7 +4058,7 @@ async function printInitSuccessBox(rootPath, flow, aiResult = null, gitnexusResu
3953
4058
  ];
3954
4059
  process.stdout.write(`${boxen5(lines.join("\n"), { padding: 1, borderStyle: "round" })}
3955
4060
  `);
3956
- const packDir = join24(rootPath, TEAM_PACK_RELATIVE_PATH);
4061
+ const packDir = join25(rootPath, TEAM_PACK_RELATIVE_PATH);
3957
4062
  if (await pathExists(packDir)) {
3958
4063
  process.stdout.write(`
3959
4064
  ${formatPackCommandsCheatsheetBox()}
@@ -3969,7 +4074,7 @@ async function getOrCreateOriginRemote(folderPath, opts) {
3969
4074
  log.success(`Folder \u0111\xE3 c\xF3 remote origin: ${origin.refs.push}`);
3970
4075
  return origin.refs.push;
3971
4076
  }
3972
- const shouldCreate = opts.createRemote ?? await confirm5({
4077
+ const shouldCreate = opts.createRemote ?? await confirm6({
3973
4078
  message: "Folder ch\u01B0a c\xF3 remote. T\u1EA1o GitHub repo ngay \u0111\u1EC3 share team?",
3974
4079
  default: true
3975
4080
  });
@@ -3978,7 +4083,7 @@ async function getOrCreateOriginRemote(folderPath, opts) {
3978
4083
  return void 0;
3979
4084
  }
3980
4085
  await ensureGitHubReady();
3981
- const visibility = opts.repoVisibility ?? await select10({
4086
+ const visibility = opts.repoVisibility ?? await select11({
3982
4087
  message: "Visibility?",
3983
4088
  choices: [
3984
4089
  { name: "private (m\u1EB7c \u0111\u1ECBnh)", value: "private" },
@@ -3987,7 +4092,7 @@ async function getOrCreateOriginRemote(folderPath, opts) {
3987
4092
  });
3988
4093
  const repoName = await input6({
3989
4094
  message: "T\xEAn repo:",
3990
- default: basename(folderPath)
4095
+ default: basename2(folderPath)
3991
4096
  });
3992
4097
  const urls = createGithubRemoteFromFolder({
3993
4098
  folder: folderPath,
@@ -4053,10 +4158,10 @@ async function finalizeWorkspaceScaffold(args) {
4053
4158
  await writeRootClaudeMd(args.workspacePath, vars);
4054
4159
  await writeProjectSettings(args.workspacePath, vars);
4055
4160
  await appendGitignoreEntries(args.workspacePath);
4056
- await ensureDir(join25(args.workspacePath, "notes"));
4057
- await ensureDir(join25(args.workspacePath, "scripts"));
4058
- await installGitHook(join25(args.workspacePath, ".git"), "post-merge");
4059
- await installGitHook(join25(args.workspacePath, ".git", "modules", "src"), "pre-push");
4161
+ await ensureDir(join26(args.workspacePath, "notes"));
4162
+ await ensureDir(join26(args.workspacePath, "scripts"));
4163
+ await installGitHook(join26(args.workspacePath, ".git"), "post-merge");
4164
+ await installGitHook(join26(args.workspacePath, ".git", "modules", "src"), "pre-push");
4060
4165
  log.success("C\xE0i post-merge (workspace) + pre-push (src/)");
4061
4166
  await autoSyncPackOnInit(args.workspacePath);
4062
4167
  await appendAuditEntry("init", `flow=${args.flow},workspace=${args.workspaceName}`);
@@ -4094,12 +4199,12 @@ async function finalizeWorkspaceScaffold(args) {
4094
4199
  await printInitSuccessBox(args.workspacePath, args.flow, aiResult, gitnexusResult);
4095
4200
  }
4096
4201
  async function autoSyncPackOnInit(workspacePath) {
4097
- const packDir = join25(workspacePath, TEAM_PACK_RELATIVE_PATH);
4202
+ const packDir = join26(workspacePath, TEAM_PACK_RELATIVE_PATH);
4098
4203
  if (!await pathExists(packDir)) {
4099
4204
  log.dim("Pack submodule kh\xF4ng t\u1ED3n t\u1EA1i (skip auto-sync). C\xF3 th\u1EC3 ch\u1EA1y `avatar sync` sau.");
4100
4205
  return;
4101
4206
  }
4102
- const claudeDir = join25(workspacePath, ".claude");
4207
+ const claudeDir = join26(workspacePath, ".claude");
4103
4208
  log.info("Auto-sync pack content v\xE0o .claude/ (symlinks + settings merge)...");
4104
4209
  try {
4105
4210
  const results = await syncAllMountDirs(packDir, claudeDir, false);
@@ -4134,13 +4239,13 @@ async function maybeCreateWorkspaceRemote(args) {
4134
4239
  let shouldCreate = args.createWorkspaceRemote;
4135
4240
  if (shouldCreate === void 0) {
4136
4241
  if (args.autoYes) return;
4137
- shouldCreate = await confirm5({
4242
+ shouldCreate = await confirm6({
4138
4243
  message: "T\u1EA1o remote GitHub cho workspace \u0111\u1EC3 share team? (Avatar state)",
4139
4244
  default: false
4140
4245
  });
4141
4246
  }
4142
4247
  if (!shouldCreate) return;
4143
- const visibility = args.repoVisibility ?? (args.autoYes ? "private" : await select10({
4248
+ const visibility = args.repoVisibility ?? (args.autoYes ? "private" : await select11({
4144
4249
  message: "Workspace visibility?",
4145
4250
  choices: [
4146
4251
  { name: "private (m\u1EB7c \u0111\u1ECBnh, an to\xE0n)", value: "private" },
@@ -4159,7 +4264,7 @@ async function maybeCreateWorkspaceRemote(args) {
4159
4264
  } catch (err) {
4160
4265
  if (err instanceof CreateWorkspaceRemoteError && err.reason === "repo-exists") {
4161
4266
  const fullName = err.fullName;
4162
- const reuseAction = await select10({
4267
+ const reuseAction = await select11({
4163
4268
  message: `Repo '${fullName}' \u0111\xE3 t\u1ED3n t\u1EA1i tr\xEAn GitHub. C\xE1ch x\u1EED l\xFD?`,
4164
4269
  choices: [
4165
4270
  {
@@ -4257,9 +4362,24 @@ async function runInitFromExistingFolder(opts, ownerEmail) {
4257
4362
  presetStrategy: parseBootstrapStrategyOpts(opts),
4258
4363
  autoYes: opts.yes
4259
4364
  });
4260
- const remoteUrl = await getOrCreateOriginRemote(folderPath, opts);
4365
+ let remoteUrl = await getOrCreateOriginRemote(folderPath, opts);
4366
+ if (remoteUrl) {
4367
+ const verify = tryVerifyGitRemoteAccessible(remoteUrl);
4368
+ if (!verify.ok) {
4369
+ log.warn(`Remote ${remoteUrl} kh\xF4ng accessible (${verify.reason ?? "unknown"}).`);
4370
+ const recovered = await handleRemoteAccessFailureWithAccountSwitch({
4371
+ url: remoteUrl,
4372
+ initialReason: verify.reason ?? "unknown",
4373
+ initialDetail: verify.detail,
4374
+ folderPath,
4375
+ // enable option "Reset folder & tạo repo mới"
4376
+ defaultVisibility: opts.repoVisibility
4377
+ });
4378
+ remoteUrl = recovered.resolvedUrl;
4379
+ }
4380
+ }
4261
4381
  const teamOwner = opts.teamOwner ?? await promptTeamOwner(ownerEmail);
4262
- const inferredName = opts.workspaceName ?? `${basename2(folderPath)}-avatar-workspace`;
4382
+ const inferredName = opts.workspaceName ?? `${basename3(folderPath)}-avatar-workspace`;
4263
4383
  const workspaceName = opts.workspaceName ?? await input7({ message: "T\xEAn workspace:", default: inferredName });
4264
4384
  const workspaceParent = resolve2(opts.workspaceParent ?? ".");
4265
4385
  const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);
@@ -4290,7 +4410,7 @@ async function runInitFromScratch(opts, ownerEmail) {
4290
4410
  message: "T\xEAn d\u1EF1 \xE1n:",
4291
4411
  validate: (v) => v.length > 0 ? true : "T\xEAn b\u1EAFt bu\u1ED9c"
4292
4412
  });
4293
- const visibility = opts.repoVisibility ?? await select11({
4413
+ const visibility = opts.repoVisibility ?? await select12({
4294
4414
  message: "Visibility?",
4295
4415
  choices: [
4296
4416
  { name: "private (m\u1EB7c \u0111\u1ECBnh)", value: "private" },
@@ -4300,7 +4420,7 @@ async function runInitFromScratch(opts, ownerEmail) {
4300
4420
  const teamOwner = opts.teamOwner ?? await promptTeamOwner(ownerEmail);
4301
4421
  const workspaceParent = resolve2(opts.workspaceParent ?? ".");
4302
4422
  const workspacePath = await resolveWorkspacePath(workspaceParent, projectName, opts.force);
4303
- const srcPath = join26(workspacePath, "src");
4423
+ const srcPath = join27(workspacePath, "src");
4304
4424
  await ensureDir(workspacePath);
4305
4425
  await ensureDir(srcPath);
4306
4426
  await safeBootstrapGitInFolder(srcPath, { autoYes: true });
@@ -4617,7 +4737,7 @@ async function runInit(opts) {
4617
4737
  }
4618
4738
  }
4619
4739
  async function promptProjectStatus() {
4620
- return await select12({
4740
+ return await select13({
4621
4741
  message: "T\xECnh tr\u1EA1ng d\u1EF1 \xE1n c\u1EE7a b\u1EA1n?",
4622
4742
  choices: [
4623
4743
  { name: "1. \u0110\xE3 c\xF3 repo git remote (URL c\xF3 s\u1EB5n)", value: "existing-remote" },
@@ -4649,7 +4769,7 @@ function registerMcpRunCommand(program2) {
4649
4769
  }
4650
4770
 
4651
4771
  // src/commands/pack-status-and-version-check.ts
4652
- import { join as join27 } from "path";
4772
+ import { join as join28 } from "path";
4653
4773
  import boxen7 from "boxen";
4654
4774
  var PACK_RELATIVE_PATH = ".claude/pack";
4655
4775
  function registerPackCommand(program2) {
@@ -4670,7 +4790,7 @@ function registerPackCommand(program2) {
4670
4790
  });
4671
4791
  }
4672
4792
  async function gatherPackStatus(cwd, doFetch) {
4673
- const packDir = join27(cwd, PACK_RELATIVE_PATH);
4793
+ const packDir = join28(cwd, PACK_RELATIVE_PATH);
4674
4794
  if (!await pathExists(packDir) || !await isGitRepo(packDir)) {
4675
4795
  return {
4676
4796
  installed: false,
@@ -4759,18 +4879,18 @@ function registerSecretsCommand(program2) {
4759
4879
  }
4760
4880
 
4761
4881
  // src/commands/status.ts
4762
- import { promises as fs13 } from "fs";
4763
- import { join as join29 } from "path";
4882
+ import { promises as fs14 } from "fs";
4883
+ import { join as join30 } from "path";
4764
4884
  import boxen8 from "boxen";
4765
4885
 
4766
4886
  // src/lib/pack-backup-manager.ts
4767
- import { promises as fs12 } from "fs";
4768
- import { join as join28 } from "path";
4887
+ import { promises as fs13 } from "fs";
4888
+ import { join as join29 } from "path";
4769
4889
  var BACKUP_DIR_NAME = "_backup";
4770
4890
  async function listBackups(projectRoot) {
4771
- const dir = join28(projectRoot, ".claude", BACKUP_DIR_NAME);
4891
+ const dir = join29(projectRoot, ".claude", BACKUP_DIR_NAME);
4772
4892
  if (!await pathExists(dir)) return [];
4773
- const entries = await fs12.readdir(dir, { withFileTypes: true });
4893
+ const entries = await fs13.readdir(dir, { withFileTypes: true });
4774
4894
  return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
4775
4895
  }
4776
4896
 
@@ -4793,7 +4913,7 @@ function registerStatusCommand(program2) {
4793
4913
  }
4794
4914
  async function gatherStatus(cwd) {
4795
4915
  const projectName = cwd.split("/").filter(Boolean).pop() ?? "unknown";
4796
- const claudeRoot = join29(cwd, ".claude");
4916
+ const claudeRoot = join30(cwd, ".claude");
4797
4917
  const hasAvatar = await pathExists(claudeRoot);
4798
4918
  if (!hasAvatar) {
4799
4919
  return {
@@ -4806,9 +4926,9 @@ async function gatherStatus(cwd) {
4806
4926
  hasAvatar: false
4807
4927
  };
4808
4928
  }
4809
- const packVersion = await isGitRepo(join29(claudeRoot, "pack")) ? await readPinnedPackVersion(cwd).catch(() => null) : null;
4810
- const pendingDir = join29(claudeRoot, "_pending");
4811
- const pendingCount = await pathExists(pendingDir) ? (await fs13.readdir(pendingDir)).filter((n) => n.endsWith(".diff.md")).length : 0;
4929
+ const packVersion = await isGitRepo(join30(claudeRoot, "pack")) ? await readPinnedPackVersion(cwd).catch(() => null) : null;
4930
+ const pendingDir = join30(claudeRoot, "_pending");
4931
+ const pendingCount = await pathExists(pendingDir) ? (await fs14.readdir(pendingDir)).filter((n) => n.endsWith(".diff.md")).length : 0;
4812
4932
  const backupCount = (await listBackups(cwd)).length;
4813
4933
  const techStackSummary = await readTechStackFirstLine(claudeRoot);
4814
4934
  return {
@@ -4822,7 +4942,7 @@ async function gatherStatus(cwd) {
4822
4942
  };
4823
4943
  }
4824
4944
  async function readTechStackFirstLine(claudeRoot) {
4825
- const techStackPath = join29(claudeRoot, "project", "tech-stack.md");
4945
+ const techStackPath = join30(claudeRoot, "project", "tech-stack.md");
4826
4946
  if (!await pathExists(techStackPath)) return "(no tech-stack.md)";
4827
4947
  const content = await readText(techStackPath);
4828
4948
  const firstNonHeaderLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#") && !l.startsWith(">"));
@@ -4843,17 +4963,17 @@ function renderStatusBox(s) {
4843
4963
  }
4844
4964
 
4845
4965
  // src/commands/sync.ts
4846
- import { join as join31 } from "path";
4966
+ import { join as join32 } from "path";
4847
4967
 
4848
4968
  // src/lib/preview-team-pack-sync-changes-for-dry-run.ts
4849
- import { join as join30 } from "path";
4969
+ import { join as join31 } from "path";
4850
4970
  async function inspectMountDir(packDir, claudeDir, dir) {
4851
- const source = join30(packDir, dir);
4852
- const dest = join30(claudeDir, dir);
4971
+ const source = join31(packDir, dir);
4972
+ const dest = join31(claudeDir, dir);
4853
4973
  if (!await pathExists(source)) return "source-missing";
4854
4974
  if (!await pathExists(dest)) return "needs-creation";
4855
- const { promises: fs14 } = await import("fs");
4856
- const st = await fs14.lstat(dest);
4975
+ const { promises: fs15 } = await import("fs");
4976
+ const st = await fs15.lstat(dest);
4857
4977
  if (st.isSymbolicLink()) return "already-linked";
4858
4978
  return "conflict-real-dir";
4859
4979
  }
@@ -4891,8 +5011,8 @@ async function buildSyncPreview(packDir, claudeDir, targetVersion) {
4891
5011
  var DEFAULT_PACK_BRANCH2 = "main";
4892
5012
  async function syncAction(opts) {
4893
5013
  const projectRoot = process.cwd();
4894
- const claudeDir = join31(projectRoot, ".claude");
4895
- const packDir = join31(projectRoot, TEAM_PACK_RELATIVE_PATH);
5014
+ const claudeDir = join32(projectRoot, ".claude");
5015
+ const packDir = join32(projectRoot, TEAM_PACK_RELATIVE_PATH);
4896
5016
  if (!await pathExists(packDir)) {
4897
5017
  log.error(
4898
5018
  `team-ai-pack submodule ch\u01B0a \u0111\u01B0\u1EE3c kh\u1EDFi t\u1EA1o \u1EDF ${TEAM_PACK_RELATIVE_PATH}/.
@@ -5027,33 +5147,33 @@ function registerToolsCommand(program2) {
5027
5147
 
5028
5148
  // src/commands/uninstall.ts
5029
5149
  import { relative as relative4 } from "path";
5030
- import { confirm as confirm6 } from "@inquirer/prompts";
5150
+ import { confirm as confirm7 } from "@inquirer/prompts";
5031
5151
  import boxen9 from "boxen";
5032
5152
 
5033
5153
  // src/lib/create-uninstall-backup-snapshot.ts
5034
5154
  import { cp, mkdir, writeFile } from "fs/promises";
5035
5155
  import { homedir as homedir4 } from "os";
5036
- import { basename as basename3, join as join32 } from "path";
5037
- var UNINSTALL_BACKUPS_DIR = join32(homedir4(), ".avatar", "uninstall-backups");
5156
+ import { basename as basename4, join as join33 } from "path";
5157
+ var UNINSTALL_BACKUPS_DIR = join33(homedir4(), ".avatar", "uninstall-backups");
5038
5158
  async function createUninstallBackupSnapshot(projectRoot, artifacts, avatarVersion) {
5039
- const projectName = basename3(projectRoot);
5159
+ const projectName = basename4(projectRoot);
5040
5160
  const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5041
- const backupDir = join32(UNINSTALL_BACKUPS_DIR, `${projectName}-${timestamp2}`);
5161
+ const backupDir = join33(UNINSTALL_BACKUPS_DIR, `${projectName}-${timestamp2}`);
5042
5162
  await mkdir(backupDir, { recursive: true, mode: 448 });
5043
5163
  if (artifacts.claudeDir) {
5044
- await cp(artifacts.claudeDir, join32(backupDir, ".claude"), { recursive: true });
5164
+ await cp(artifacts.claudeDir, join33(backupDir, ".claude"), { recursive: true });
5045
5165
  }
5046
5166
  if (artifacts.claudeMd) {
5047
- await cp(artifacts.claudeMd, join32(backupDir, "CLAUDE.md"));
5167
+ await cp(artifacts.claudeMd, join33(backupDir, "CLAUDE.md"));
5048
5168
  }
5049
5169
  if (artifacts.postMergeHook || artifacts.prePushHook) {
5050
- const hooksBackupDir = join32(backupDir, "hooks");
5170
+ const hooksBackupDir = join33(backupDir, "hooks");
5051
5171
  await mkdir(hooksBackupDir, { recursive: true });
5052
5172
  if (artifacts.postMergeHook) {
5053
- await cp(artifacts.postMergeHook, join32(hooksBackupDir, "post-merge"));
5173
+ await cp(artifacts.postMergeHook, join33(hooksBackupDir, "post-merge"));
5054
5174
  }
5055
5175
  if (artifacts.prePushHook) {
5056
- await cp(artifacts.prePushHook, join32(hooksBackupDir, "pre-push"));
5176
+ await cp(artifacts.prePushHook, join33(hooksBackupDir, "pre-push"));
5057
5177
  }
5058
5178
  }
5059
5179
  const manifest = {
@@ -5068,27 +5188,27 @@ async function createUninstallBackupSnapshot(projectRoot, artifacts, avatarVersi
5068
5188
  prePushHook: !!artifacts.prePushHook
5069
5189
  }
5070
5190
  };
5071
- await writeFile(join32(backupDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
5191
+ await writeFile(join33(backupDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
5072
5192
  return backupDir;
5073
5193
  }
5074
5194
 
5075
5195
  // src/lib/detect-avatar-project-artifacts.ts
5076
5196
  import { existsSync as existsSync9 } from "fs";
5077
- import { join as join33 } from "path";
5197
+ import { join as join34 } from "path";
5078
5198
  function existsOrNull(path) {
5079
5199
  return existsSync9(path) ? path : null;
5080
5200
  }
5081
5201
  function detectAvatarProjectArtifacts(projectRoot) {
5082
- const claudeDir = existsOrNull(join33(projectRoot, ".claude"));
5083
- const claudeMd = existsOrNull(join33(projectRoot, "CLAUDE.md"));
5084
- const postMergeHook = existsOrNull(join33(projectRoot, ".git", "hooks", "post-merge"));
5202
+ const claudeDir = existsOrNull(join34(projectRoot, ".claude"));
5203
+ const claudeMd = existsOrNull(join34(projectRoot, "CLAUDE.md"));
5204
+ const postMergeHook = existsOrNull(join34(projectRoot, ".git", "hooks", "post-merge"));
5085
5205
  const prePushHook = existsOrNull(
5086
- join33(projectRoot, ".git", "modules", "src", "hooks", "pre-push")
5206
+ join34(projectRoot, ".git", "modules", "src", "hooks", "pre-push")
5087
5207
  );
5088
- const gitignorePath = existsOrNull(join33(projectRoot, ".gitignore"));
5089
- const gitmodulesPath = existsOrNull(join33(projectRoot, ".gitmodules"));
5090
- const notesDir = existsOrNull(join33(projectRoot, "notes"));
5091
- const scriptsDir = existsOrNull(join33(projectRoot, "scripts"));
5208
+ const gitignorePath = existsOrNull(join34(projectRoot, ".gitignore"));
5209
+ const gitmodulesPath = existsOrNull(join34(projectRoot, ".gitmodules"));
5210
+ const notesDir = existsOrNull(join34(projectRoot, "notes"));
5211
+ const scriptsDir = existsOrNull(join34(projectRoot, "scripts"));
5092
5212
  const hasAnyArtifact = !!(claudeDir || claudeMd || postMergeHook || prePushHook);
5093
5213
  return {
5094
5214
  hasAnyArtifact,
@@ -5109,11 +5229,11 @@ async function executeUninstallDeletion(artifacts, flags) {
5109
5229
  if (artifacts.claudeDir) {
5110
5230
  if (flags.keepSubmodule) {
5111
5231
  const { readdir: readdir2 } = await import("fs/promises");
5112
- const { join: join34 } = await import("path");
5232
+ const { join: join35 } = await import("path");
5113
5233
  const entries = await readdir2(artifacts.claudeDir);
5114
5234
  for (const entry of entries) {
5115
5235
  if (entry === "pack") continue;
5116
- await rm(join34(artifacts.claudeDir, entry), { recursive: true, force: true });
5236
+ await rm(join35(artifacts.claudeDir, entry), { recursive: true, force: true });
5117
5237
  }
5118
5238
  } else {
5119
5239
  await rm(artifacts.claudeDir, { recursive: true, force: true });
@@ -5206,7 +5326,7 @@ async function runUninstall(opts) {
5206
5326
  return;
5207
5327
  }
5208
5328
  if (!opts.yes) {
5209
- const ok = await confirm6({
5329
+ const ok = await confirm7({
5210
5330
  message: "Ti\u1EBFp t\u1EE5c g\u1EE1 Avatar?",
5211
5331
  default: false
5212
5332
  });