@nalvietnam/avatar-cli 1.2.0 → 1.2.1
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
|
@@ -157,8 +157,17 @@ function spinner(text) {
|
|
|
157
157
|
var QUOTA_VERIFY_TIMEOUT_MS = 3e4;
|
|
158
158
|
var QUOTA_VERIFY_PROMPT = "ok";
|
|
159
159
|
function checkClaudeCodeSubscriptionAuth() {
|
|
160
|
-
const result = spawnSync("claude", ["auth", "status"], {
|
|
160
|
+
const result = spawnSync("claude", ["auth", "status"], { encoding: "utf8" });
|
|
161
161
|
if (result.error || result.status !== 0) return "not-authenticated";
|
|
162
|
+
const stdout = (result.stdout || "").trim();
|
|
163
|
+
if (stdout.startsWith("{")) {
|
|
164
|
+
try {
|
|
165
|
+
const parsed = JSON.parse(stdout);
|
|
166
|
+
return parsed.loggedIn === true ? "authenticated" : "not-authenticated";
|
|
167
|
+
} catch {
|
|
168
|
+
return "authenticated";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
162
171
|
return "authenticated";
|
|
163
172
|
}
|
|
164
173
|
function triggerClaudeCodeAuthLogin() {
|
|
@@ -179,14 +188,37 @@ function classifyQuotaError(combinedOutput) {
|
|
|
179
188
|
if (text.includes("insufficient_quota") || text.includes("insufficient quota")) {
|
|
180
189
|
return "insufficient_quota";
|
|
181
190
|
}
|
|
191
|
+
if (text.includes("quota_exceeded") || text.includes("quota exceeded") || text.includes("usage limit") || text.includes("you've used all")) {
|
|
192
|
+
return "insufficient_quota";
|
|
193
|
+
}
|
|
194
|
+
if (text.includes("401") || text.includes("invalid authentication") || text.includes("authentication credentials") || text.includes("failed to authenticate") || text.includes("authentication failed") || text.includes("unauthorized")) {
|
|
195
|
+
return "auth-expired";
|
|
196
|
+
}
|
|
182
197
|
if (text.includes("invalid_api_key") || text.includes("invalid api key")) {
|
|
183
198
|
return "invalid_api_key";
|
|
184
199
|
}
|
|
185
|
-
if (text.includes("rate_limit") || text.includes("rate limit")) {
|
|
200
|
+
if (text.includes("rate_limit") || text.includes("rate limit") || text.includes("429")) {
|
|
186
201
|
return "rate_limit";
|
|
187
202
|
}
|
|
188
203
|
return "unknown";
|
|
189
204
|
}
|
|
205
|
+
function getQuotaErrorHint(reason) {
|
|
206
|
+
switch (reason) {
|
|
207
|
+
case "auth-expired":
|
|
208
|
+
return "Token Claude Code \u0111\xE3 h\u1EBFt h\u1EA1n/b\u1ECB revoke. Ch\u1EA1y: `claude auth logout && claude auth login`.";
|
|
209
|
+
case "credit_balance_too_low":
|
|
210
|
+
case "insufficient_quota":
|
|
211
|
+
return "H\u1EBFt quota subscription. Upgrade plan ho\u1EB7c d\xF9ng LLMLite (avatar ai setup \u2192 ch\u1ECDn LLMLite).";
|
|
212
|
+
case "invalid_api_key":
|
|
213
|
+
return "API key invalid. Re-login: `claude auth login`.";
|
|
214
|
+
case "rate_limit":
|
|
215
|
+
return "B\u1ECB rate limit t\u1EA1m th\u1EDDi. Ch\u1EDD v\xE0i ph\xFAt r\u1ED3i ch\u1EA1y `avatar ai setup`.";
|
|
216
|
+
case "timeout":
|
|
217
|
+
return "Network ch\u1EADm ho\u1EB7c Anthropic API down. Check m\u1EA1ng r\u1ED3i ch\u1EA1y l\u1EA1i.";
|
|
218
|
+
default:
|
|
219
|
+
return "L\u1ED7i ch\u01B0a bi\u1EBFt. Xem stderr \u1EDF tr\xEAn + ch\u1EA1y `claude --print ok` tay \u0111\u1EC3 debug.";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
190
222
|
function verifyClaudeCodeQuota() {
|
|
191
223
|
const result = spawnSync("claude", ["--print", QUOTA_VERIFY_PROMPT], {
|
|
192
224
|
encoding: "utf8",
|
|
@@ -202,6 +234,9 @@ function verifyClaudeCodeQuota() {
|
|
|
202
234
|
}
|
|
203
235
|
const reason = classifyQuotaError(`${stderr}
|
|
204
236
|
${stdout}`);
|
|
237
|
+
if (reason === "unknown" && stderr.trim()) {
|
|
238
|
+
log.dim(`[debug] claude --print stderr: ${stderr.slice(0, 500)}`);
|
|
239
|
+
}
|
|
205
240
|
return { ok: false, reason, detail: stderr.slice(0, 500) };
|
|
206
241
|
}
|
|
207
242
|
|
|
@@ -221,12 +256,8 @@ var VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
|
221
256
|
var SEMVER_REGEX = /(\d+\.\d+\.\d+)/;
|
|
222
257
|
function probeClaudeBinaryPath() {
|
|
223
258
|
const isWindows = detectHostPlatform() === "win32";
|
|
224
|
-
const probeCmd = isWindows ? "where" : "
|
|
225
|
-
const
|
|
226
|
-
const result = spawnSync2(probeCmd, probeArgs, {
|
|
227
|
-
encoding: "utf8",
|
|
228
|
-
shell: !isWindows
|
|
229
|
-
});
|
|
259
|
+
const probeCmd = isWindows ? "where" : "which";
|
|
260
|
+
const result = spawnSync2(probeCmd, ["claude"], { encoding: "utf8" });
|
|
230
261
|
if (result.error || result.status !== 0) return null;
|
|
231
262
|
const out = (result.stdout || "").trim();
|
|
232
263
|
if (!out) return null;
|
|
@@ -562,16 +593,21 @@ async function runAiSetupPhase(args) {
|
|
|
562
593
|
if (checkClaudeCodeSubscriptionAuth() !== "authenticated") {
|
|
563
594
|
triggerClaudeCodeAuthLogin();
|
|
564
595
|
}
|
|
565
|
-
|
|
596
|
+
let quota = verifyClaudeCodeQuota();
|
|
597
|
+
if (!quota.ok && quota.reason === "auth-expired") {
|
|
598
|
+
log.warn("Token Claude Code \u0111\xE3 h\u1EBFt h\u1EA1n. T\u1EF1 \u0111\u1ED9ng re-login...");
|
|
599
|
+
triggerClaudeCodeAuthLogin();
|
|
600
|
+
quota = verifyClaudeCodeQuota();
|
|
601
|
+
}
|
|
566
602
|
if (!quota.ok) {
|
|
603
|
+
const reason = quota.reason ?? "unknown";
|
|
567
604
|
await appendAuditEntry(
|
|
568
605
|
"ai_setup",
|
|
569
|
-
`provider=subscription,result=no-quota,reason=${
|
|
570
|
-
);
|
|
571
|
-
log.warn(
|
|
572
|
-
`Subscription verify th\u1EA5t b\u1EA1i (${quota.reason ?? "unknown"}). Suggest LLMLite ho\u1EB7c upgrade plan.`
|
|
606
|
+
`provider=subscription,result=no-quota,reason=${reason}`
|
|
573
607
|
);
|
|
574
|
-
|
|
608
|
+
log.warn(`Subscription verify th\u1EA5t b\u1EA1i (${reason}).`);
|
|
609
|
+
log.dim(`\u2192 ${getQuotaErrorHint(reason)}`);
|
|
610
|
+
return { ok: false, reason: `subscription-${reason}`, phase: "quota" };
|
|
575
611
|
}
|
|
576
612
|
await writeClaudeSettings(args.workspacePath, {
|
|
577
613
|
provider: "subscription",
|
|
@@ -2590,7 +2626,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
|
|
|
2590
2626
|
}
|
|
2591
2627
|
|
|
2592
2628
|
// src/commands/uninstall.ts
|
|
2593
|
-
var CLI_VERSION = "1.2.
|
|
2629
|
+
var CLI_VERSION = "1.2.1";
|
|
2594
2630
|
function registerUninstallCommand(program2) {
|
|
2595
2631
|
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) => {
|
|
2596
2632
|
try {
|
|
@@ -2672,7 +2708,7 @@ function printUninstallSuccessBox(backupPath) {
|
|
|
2672
2708
|
}
|
|
2673
2709
|
|
|
2674
2710
|
// src/index.ts
|
|
2675
|
-
var CLI_VERSION2 = "1.2.
|
|
2711
|
+
var CLI_VERSION2 = "1.2.1";
|
|
2676
2712
|
var program = new Command();
|
|
2677
2713
|
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(
|
|
2678
2714
|
"beforeAll",
|