@nalvietnam/avatar-cli 1.4.0 → 1.4.2

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
@@ -183,6 +183,33 @@ function spinner(text) {
183
183
  isEnabled: process.stdout.isTTY ?? false
184
184
  }).start();
185
185
  }
186
+ function spinnerWithElapsed(prefix) {
187
+ const startMs = Date.now();
188
+ const sp = spinner(`${prefix} (0:00)`);
189
+ const formatElapsed = () => {
190
+ const sec = Math.floor((Date.now() - startMs) / 1e3);
191
+ const m = Math.floor(sec / 60);
192
+ const s = sec % 60;
193
+ return `${m}:${String(s).padStart(2, "0")}`;
194
+ };
195
+ const interval = setInterval(() => {
196
+ sp.text = `${prefix} (${formatElapsed()})`;
197
+ }, 1e3);
198
+ return {
199
+ succeed: (text) => {
200
+ clearInterval(interval);
201
+ sp.succeed(`${text} (${formatElapsed()})`);
202
+ },
203
+ fail: (text) => {
204
+ clearInterval(interval);
205
+ sp.fail(`${text} (${formatElapsed()})`);
206
+ },
207
+ stop: () => {
208
+ clearInterval(interval);
209
+ sp.stop();
210
+ }
211
+ };
212
+ }
186
213
 
187
214
  // src/lib/check-claude-code-subscription-and-quota.ts
188
215
  var QUOTA_VERIFY_TIMEOUT_MS = 3e4;
@@ -1359,44 +1386,57 @@ function classifyOperationFailure(operation, exitCode, signal, stderrSample) {
1359
1386
  stderrSample
1360
1387
  );
1361
1388
  }
1389
+ function tailLines(text, n) {
1390
+ const lines = text.split("\n");
1391
+ return lines.slice(-n).join("\n");
1392
+ }
1362
1393
  function runGitnexusSetup() {
1363
- log.info("Setup GitNexus global skills (~/.claude/skills/gitnexus-*)...");
1394
+ const sp = spinnerWithElapsed("Setup GitNexus global skills (~/.claude/skills/gitnexus-*)");
1364
1395
  const result = spawnSync7("gitnexus", ["setup"], {
1365
- stdio: ["inherit", "inherit", "pipe"],
1396
+ stdio: ["ignore", "pipe", "pipe"],
1366
1397
  timeout: SETUP_TIMEOUT_MS,
1367
1398
  encoding: "utf8"
1368
1399
  });
1369
1400
  if (result.status !== 0 || result.signal === "SIGTERM") {
1401
+ sp.fail("GitNexus setup failed");
1370
1402
  const stderr = (result.stderr || "").trim();
1371
- if (stderr) process.stderr.write(`${stderr}
1403
+ const stdout = (result.stdout || "").trim();
1404
+ if (stderr) process.stderr.write(`${tailLines(stderr, 30)}
1405
+ `);
1406
+ else if (stdout) process.stderr.write(`${tailLines(stdout, 30)}
1372
1407
  `);
1373
1408
  throw classifyOperationFailure("setup", result.status, result.signal, stderr);
1374
1409
  }
1375
- log.success("GitNexus setup OK (global skills installed)");
1410
+ sp.succeed("GitNexus setup OK (global skills installed)");
1376
1411
  }
1377
1412
  function runGitnexusAnalyze(workspacePath) {
1378
- log.info(`Analyze workspace ${workspacePath} (c\xF3 th\u1EC3 1-3 ph\xFAt)...`);
1413
+ const sp = spinnerWithElapsed(`Analyze workspace ${workspacePath} (1-3 ph\xFAt)`);
1379
1414
  const result = spawnSync7("gitnexus", ["analyze", "."], {
1380
1415
  cwd: workspacePath,
1381
- stdio: ["inherit", "inherit", "pipe"],
1416
+ stdio: ["ignore", "pipe", "pipe"],
1382
1417
  timeout: ANALYZE_TIMEOUT_MS,
1383
1418
  encoding: "utf8"
1384
1419
  });
1385
1420
  if (result.status !== 0 || result.signal === "SIGTERM") {
1421
+ sp.fail("Analyze failed");
1386
1422
  const stderr = (result.stderr || "").trim();
1387
- if (stderr) process.stderr.write(`${stderr}
1423
+ const stdout = (result.stdout || "").trim();
1424
+ if (stderr) process.stderr.write(`${tailLines(stderr, 30)}
1425
+ `);
1426
+ else if (stdout) process.stderr.write(`${tailLines(stdout, 30)}
1388
1427
  `);
1389
1428
  throw classifyOperationFailure("analyze", result.status, result.signal, stderr);
1390
1429
  }
1391
1430
  const metaPath = join12(workspacePath, ".gitnexus", "meta.json");
1392
1431
  if (!existsSync4(metaPath)) {
1432
+ sp.fail("Analyze exit 0 nh\u01B0ng kh\xF4ng th\u1EA5y meta.json");
1393
1433
  throw new GitnexusOperationError(
1394
1434
  "analyze",
1395
1435
  "missing-output",
1396
1436
  `gitnexus analyze xong nh\u01B0ng kh\xF4ng th\u1EA5y ${metaPath}. Repo c\xF3 th\u1EC3 empty ho\u1EB7c gitnexus fail silent.`
1397
1437
  );
1398
1438
  }
1399
- log.success(`Analyze OK (index t\u1EA1i ${join12(workspacePath, ".gitnexus")})`);
1439
+ sp.succeed(`Analyze OK (index t\u1EA1i ${join12(workspacePath, ".gitnexus")})`);
1400
1440
  }
1401
1441
 
1402
1442
  // src/lib/run-gitnexus-setup-phase.ts
@@ -1590,6 +1630,7 @@ import { existsSync as existsSync5 } from "fs";
1590
1630
  import { join as join14 } from "path";
1591
1631
  import { confirm as confirm2 } from "@inquirer/prompts";
1592
1632
  var WIKI_TIMEOUT_MS = 15 * 60 * 1e3;
1633
+ var DEFAULT_LLMLITE_MODEL = "nal-claude";
1593
1634
  async function readSettingsForWikiCredentials(workspacePath) {
1594
1635
  const settingsPath = join14(workspacePath, ".claude", "settings.json");
1595
1636
  if (!await pathExists(settingsPath)) return null;
@@ -1599,17 +1640,22 @@ async function readSettingsForWikiCredentials(workspacePath) {
1599
1640
  const apiKey = typeof env.ANTHROPIC_AUTH_TOKEN === "string" ? env.ANTHROPIC_AUTH_TOKEN : null;
1600
1641
  const baseUrl = typeof env.ANTHROPIC_BASE_URL === "string" ? env.ANTHROPIC_BASE_URL : null;
1601
1642
  if (!apiKey || !baseUrl) return null;
1602
- return { apiKey, baseUrl };
1643
+ const model = typeof env.ANTHROPIC_MODEL === "string" && env.ANTHROPIC_MODEL.length > 0 ? env.ANTHROPIC_MODEL : DEFAULT_LLMLITE_MODEL;
1644
+ return { apiKey, baseUrl, model };
1603
1645
  } catch {
1604
1646
  return null;
1605
1647
  }
1606
1648
  }
1607
- async function confirmWikiGeneration(baseUrl) {
1649
+ async function confirmWikiGeneration(baseUrl, model) {
1608
1650
  return await confirm2({
1609
- message: `Generate wiki cho workspace? (~$0.50 qua ${baseUrl}, 2-5 ph\xFAt). Continue?`,
1651
+ message: `Generate wiki cho workspace? (~$0.50 qua ${baseUrl} model=${model}, 2-5 ph\xFAt). Continue?`,
1610
1652
  default: true
1611
1653
  });
1612
1654
  }
1655
+ function tailLines2(text, n) {
1656
+ const lines = text.split("\n");
1657
+ return lines.slice(-n).join("\n");
1658
+ }
1613
1659
  async function runGitnexusWikiConditional(workspacePath) {
1614
1660
  const creds = await readSettingsForWikiCredentials(workspacePath);
1615
1661
  if (!creds) {
@@ -1617,29 +1663,33 @@ async function runGitnexusWikiConditional(workspacePath) {
1617
1663
  log.dim("\u0110\u1EC3 gen wiki sau, ch\u1EA1y manual: gitnexus wiki . --api-key <openai-key>");
1618
1664
  return { ran: false, skipped: true, reason: "subscription-mode" };
1619
1665
  }
1620
- const proceed = await confirmWikiGeneration(creds.baseUrl);
1666
+ const proceed = await confirmWikiGeneration(creds.baseUrl, creds.model);
1621
1667
  if (!proceed) {
1622
1668
  log.dim(
1623
1669
  "User decline wiki gen \u2014 workspace OK kh\xF4ng c\xF3 wiki. Ch\u1EA1y `gitnexus wiki` manual sau khi c\u1EA7n."
1624
1670
  );
1625
1671
  return { ran: false, skipped: true, reason: "user-declined" };
1626
1672
  }
1627
- log.info(`Generating wiki via ${creds.baseUrl} (2-5 ph\xFAt)...`);
1673
+ const sp = spinnerWithElapsed(`Generating wiki via ${creds.baseUrl} model=${creds.model}`);
1628
1674
  const result = spawnSync10(
1629
1675
  "gitnexus",
1630
- ["wiki", ".", "--api-key", creds.apiKey, "--base-url", creds.baseUrl],
1676
+ ["wiki", ".", "--api-key", creds.apiKey, "--base-url", creds.baseUrl, "--model", creds.model],
1631
1677
  {
1632
1678
  cwd: workspacePath,
1633
- stdio: ["inherit", "inherit", "pipe"],
1679
+ stdio: ["ignore", "pipe", "pipe"],
1634
1680
  timeout: WIKI_TIMEOUT_MS,
1635
1681
  encoding: "utf8"
1636
1682
  }
1637
1683
  );
1638
1684
  if (result.status !== 0 || result.signal === "SIGTERM") {
1685
+ const reason = result.signal === "SIGTERM" ? "timeout" : "non-zero-exit";
1686
+ sp.fail(`Wiki gen ${reason} (exit ${result.status ?? "null"})`);
1639
1687
  const stderr = (result.stderr || "").trim();
1640
- if (stderr) process.stderr.write(`${stderr}
1688
+ const stdout = (result.stdout || "").trim();
1689
+ if (stderr) process.stderr.write(`${tailLines2(stderr, 30)}
1690
+ `);
1691
+ else if (stdout) process.stderr.write(`${tailLines2(stdout, 30)}
1641
1692
  `);
1642
- const reason = result.signal === "SIGTERM" ? "timeout" : "non-zero-exit";
1643
1693
  return {
1644
1694
  ran: false,
1645
1695
  skipped: true,
@@ -1649,6 +1699,7 @@ async function runGitnexusWikiConditional(workspacePath) {
1649
1699
  }
1650
1700
  const wikiPath = join14(workspacePath, ".gitnexus", "wiki", "index.html");
1651
1701
  if (!existsSync5(wikiPath)) {
1702
+ sp.fail("Wiki exit 0 nh\u01B0ng kh\xF4ng th\u1EA5y index.html");
1652
1703
  return {
1653
1704
  ran: false,
1654
1705
  skipped: true,
@@ -1656,7 +1707,7 @@ async function runGitnexusWikiConditional(workspacePath) {
1656
1707
  detail: `Wiki exit 0 nh\u01B0ng kh\xF4ng th\u1EA5y ${wikiPath}`
1657
1708
  };
1658
1709
  }
1659
- log.success(`Wiki ready: ${wikiPath}`);
1710
+ sp.succeed(`Wiki ready: ${wikiPath}`);
1660
1711
  return { ran: true, skipped: false, wikiPath };
1661
1712
  }
1662
1713
 
@@ -4132,7 +4183,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
4132
4183
  }
4133
4184
 
4134
4185
  // src/commands/uninstall.ts
4135
- var CLI_VERSION = "1.4.0";
4186
+ var CLI_VERSION = "1.4.2";
4136
4187
  function registerUninstallCommand(program2) {
4137
4188
  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) => {
4138
4189
  try {
@@ -4214,7 +4265,7 @@ function printUninstallSuccessBox(backupPath) {
4214
4265
  }
4215
4266
 
4216
4267
  // src/index.ts
4217
- var CLI_VERSION2 = "1.4.0";
4268
+ var CLI_VERSION2 = "1.4.2";
4218
4269
  var program = new Command();
4219
4270
  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(
4220
4271
  "beforeAll",