@nalvietnam/avatar-cli 1.12.0 → 1.12.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
@@ -223,21 +223,27 @@ function spinnerWithElapsed(prefix) {
223
223
  }
224
224
 
225
225
  // src/lib/check-claude-code-subscription-and-quota.ts
226
- var QUOTA_VERIFY_TIMEOUT_MS = 3e4;
226
+ var QUOTA_VERIFY_TIMEOUT_MS = 6e4;
227
227
  var QUOTA_VERIFY_PROMPT = "ok";
228
- function checkClaudeCodeSubscriptionAuth() {
228
+ function readClaudeCodeAuthInfo() {
229
229
  const result = spawnSync("claude", ["auth", "status"], { encoding: "utf8" });
230
- if (result.error || result.status !== 0) return "not-authenticated";
230
+ if (result.error || result.status !== 0) return { state: "not-authenticated" };
231
231
  const stdout = (result.stdout || "").trim();
232
- if (stdout.startsWith("{")) {
233
- try {
234
- const parsed = JSON.parse(stdout);
235
- return parsed.loggedIn === true ? "authenticated" : "not-authenticated";
236
- } catch {
237
- return "authenticated";
238
- }
232
+ if (!stdout.startsWith("{")) {
233
+ return { state: "authenticated" };
234
+ }
235
+ try {
236
+ const parsed = JSON.parse(stdout);
237
+ if (parsed.loggedIn !== true) return { state: "not-authenticated" };
238
+ return {
239
+ state: "authenticated",
240
+ email: parsed.email,
241
+ subscriptionType: parsed.subscriptionType,
242
+ apiProvider: parsed.apiProvider
243
+ };
244
+ } catch {
245
+ return { state: "authenticated" };
239
246
  }
240
- return "authenticated";
241
247
  }
242
248
  function triggerClaudeCodeAuthLogin() {
243
249
  log.info("Kh\u1EDFi \u0111\u1ED9ng \u0111\u0103ng nh\u1EADp Claude Code (browser s\u1EBD m\u1EDF)...");
@@ -283,7 +289,7 @@ function getQuotaErrorHint(reason) {
283
289
  case "rate_limit":
284
290
  return "B\u1ECB rate limit t\u1EA1m th\u1EDDi. Ch\u1EDD v\xE0i ph\xFAt r\u1ED3i ch\u1EA1y `avatar ai setup`.";
285
291
  case "timeout":
286
- return "Network ch\u1EADm ho\u1EB7c Anthropic API down. Check m\u1EA1ng r\u1ED3i ch\u1EA1y l\u1EA1i.";
292
+ return "Timeout 60s: (1) m\u1EA1ng VN ch\u1EADm \u2014 th\u1EED VPN, (2) Anthropic API spike \u2014 retry v\xE0i ph\xFAt, (3) token v\u1EABn auth nh\u01B0ng quota h\u1EBFt \xE2m th\u1EA7m \u2014 check t\u1EA1i claude.ai/settings/usage.";
287
293
  default:
288
294
  return "L\u1ED7i ch\u01B0a bi\u1EBFt. Xem stderr \u1EDF tr\xEAn + ch\u1EA1y `claude --print ok` tay \u0111\u1EC3 debug.";
289
295
  }
@@ -294,8 +300,13 @@ function verifyClaudeCodeQuota() {
294
300
  timeout: QUOTA_VERIFY_TIMEOUT_MS,
295
301
  stdio: ["ignore", "pipe", "pipe"]
296
302
  });
297
- if (result.signal === "SIGTERM") {
298
- return { ok: false, reason: "timeout", detail: "claude --print > 30s" };
303
+ const isTimeout = result.signal === "SIGTERM" || result.status === 143 || result.error?.code === "ETIMEDOUT";
304
+ if (isTimeout) {
305
+ return {
306
+ ok: false,
307
+ reason: "timeout",
308
+ detail: `claude --print > ${QUOTA_VERIFY_TIMEOUT_MS / 1e3}s (m\u1EA1ng ch\u1EADm / API rate limit / token revoked kh\xF4ng return error)`
309
+ };
299
310
  }
300
311
  const stderr = result.stderr || "";
301
312
  const stdout = result.stdout || "";
@@ -802,15 +813,48 @@ async function runAiSetupPhase(args) {
802
813
  const choice = await promptAiProviderChoice(globalInfo);
803
814
  switch (choice) {
804
815
  case "subscription": {
805
- if (checkClaudeCodeSubscriptionAuth() !== "authenticated") {
816
+ let authInfo = readClaudeCodeAuthInfo();
817
+ if (authInfo.state !== "authenticated") {
806
818
  triggerClaudeCodeAuthLogin();
819
+ authInfo = readClaudeCodeAuthInfo();
807
820
  }
821
+ if (authInfo.state === "authenticated" && authInfo.subscriptionType) {
822
+ await writeClaudeSettings(args.workspacePath, {
823
+ provider: "subscription",
824
+ model: SUBSCRIPTION_DEFAULT_MODEL
825
+ });
826
+ await appendAuditEntry(
827
+ "ai_setup",
828
+ `provider=subscription,result=ok,plan=${authInfo.subscriptionType},probe=skipped`
829
+ );
830
+ log.success(
831
+ `AI ready \xB7 Subscription (${authInfo.subscriptionType}) \xB7 model=${SUBSCRIPTION_DEFAULT_MODEL}`
832
+ );
833
+ return { ok: true, provider: "subscription", model: SUBSCRIPTION_DEFAULT_MODEL };
834
+ }
835
+ log.dim("Auth status kh\xF4ng tr\u1EA3 subscriptionType \u2014 verify quota (30-60s)...");
808
836
  let quota = verifyClaudeCodeQuota();
809
837
  if (!quota.ok && quota.reason === "auth-expired") {
810
838
  log.warn("Token Claude Code \u0111\xE3 h\u1EBFt h\u1EA1n. T\u1EF1 \u0111\u1ED9ng re-login...");
811
839
  triggerClaudeCodeAuthLogin();
812
840
  quota = verifyClaudeCodeQuota();
813
841
  }
842
+ if (!quota.ok && (quota.reason === "timeout" || quota.reason === "unknown")) {
843
+ log.warn(`Probe verify ${quota.reason} \u2014 accept trust auth status. Ti\u1EBFp t\u1EE5c.`);
844
+ if (quota.detail?.trim()) log.warn(` Chi ti\u1EBFt: ${quota.detail.slice(0, 200)}`);
845
+ await writeClaudeSettings(args.workspacePath, {
846
+ provider: "subscription",
847
+ model: SUBSCRIPTION_DEFAULT_MODEL
848
+ });
849
+ await appendAuditEntry(
850
+ "ai_setup",
851
+ `provider=subscription,result=ok,probe=${quota.reason}-soft-pass`
852
+ );
853
+ log.success(
854
+ `AI ready \xB7 Subscription (probe ${quota.reason}, soft-pass) \xB7 model=${SUBSCRIPTION_DEFAULT_MODEL}`
855
+ );
856
+ return { ok: true, provider: "subscription", model: SUBSCRIPTION_DEFAULT_MODEL };
857
+ }
814
858
  if (!quota.ok) {
815
859
  const reason = quota.reason ?? "unknown";
816
860
  await appendAuditEntry(
@@ -818,9 +862,7 @@ async function runAiSetupPhase(args) {
818
862
  `provider=subscription,result=no-quota,reason=${reason}`
819
863
  );
820
864
  log.warn(`Subscription verify th\u1EA5t b\u1EA1i (${reason}).`);
821
- if (quota.detail?.trim()) {
822
- log.warn(` Chi ti\u1EBFt: ${quota.detail.slice(0, 200)}`);
823
- }
865
+ if (quota.detail?.trim()) log.warn(` Chi ti\u1EBFt: ${quota.detail.slice(0, 200)}`);
824
866
  log.warn(` \u2192 ${getQuotaErrorHint(reason)}`);
825
867
  return { ok: false, reason: `subscription-${reason}`, phase: "quota" };
826
868
  }