@hienlh/ppm 0.12.1 → 0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.12.2] - 2026-04-20
4
+
5
+ ### Fixed
6
+ - **Quota exhaustion auto-retry**: Detect "You've hit your limit" SDK message as rate limit — triggers account rotation and retry instead of showing raw error
7
+ - **False success on error results**: `onSuccess()` no longer called when SDK result has error subtype, preventing failed accounts from staying active
8
+ - **Assistant text quota detection**: Detect quota limit messages in assistant text content (not just error field), covering all SDK delivery paths
9
+
3
10
  ## [0.12.1] - 2026-04-20
4
11
 
5
12
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -228,7 +228,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
228
228
  // SDK uses `errors: string[]` array for error details
229
229
  const errorsArr = Array.isArray(e.errors) ? (e.errors as string[]).join(" ") : "";
230
230
  const msg = errorsArr || String(e.error ?? "");
231
- if (msg.includes("429") || msg.toLowerCase().includes("rate limit") || msg.toLowerCase().includes("overloaded")) return 429;
231
+ if (msg.includes("429") || msg.toLowerCase().includes("rate limit") || msg.toLowerCase().includes("overloaded") || msg.toLowerCase().includes("hit your limit")) return 429;
232
232
  if (msg.includes("401") || msg.toLowerCase().includes("unauthorized") || msg.toLowerCase().includes("invalid api key")) return 401;
233
233
  }
234
234
  return null;
@@ -1080,6 +1080,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
1080
1080
  if (textContent && /API Error:\s*401\b.*authentication_error/i.test(textContent)) {
1081
1081
  assistantError = "authentication_failed";
1082
1082
  console.warn(`[sdk] session=${sessionId} detected 401 in assistant text content — treating as auth error`);
1083
+ } else if (textContent && /hit your limit|you've hit your limit/i.test(textContent)) {
1084
+ assistantError = "rate_limit";
1085
+ console.warn(`[sdk] session=${sessionId} detected quota limit in assistant text content — treating as rate_limit`);
1083
1086
  }
1084
1087
  }
1085
1088
 
@@ -1299,7 +1302,12 @@ export class ClaudeAgentSdkProvider implements AIProvider {
1299
1302
  accountSelector.onAuthError(account.id);
1300
1303
  }
1301
1304
  } else {
1302
- accountSelector.onSuccess(account.id);
1305
+ // Only mark success when the result is actually successful,
1306
+ // not for unrecognized error subtypes (e.g. quota exhaustion)
1307
+ const resultSub = (msg as any).subtype as string | undefined;
1308
+ if (!resultSub || resultSub === "success") {
1309
+ accountSelector.onSuccess(account.id);
1310
+ }
1303
1311
  }
1304
1312
  }
1305
1313
 
@@ -1370,6 +1378,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
1370
1378
  hint = "\n\nHint: Network connectivity issue. Check your internet connection and firewall/proxy settings.";
1371
1379
  } else if (detailLower.includes("401") || detailLower.includes("unauthorized") || detailLower.includes("invalid api key")) {
1372
1380
  hint = "\n\nHint: Authentication failed. Try re-adding your account in Settings → Accounts.";
1381
+ } else if (detailLower.includes("hit your limit")) {
1382
+ hint = "\n\nHint: Account quota exhausted. Will auto-switch on next message if other accounts are available.";
1373
1383
  }
1374
1384
  const fullMsg = sdkDetail ? `${baseMsg}\n${sdkDetail}${hint}` : baseMsg;
1375
1385
  yield {