@bacnh85/pi-sub 0.1.30 → 0.1.31

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,3 +1,15 @@
1
+ ## 0.1.31 (2026-08-22)
2
+
3
+ - **Fixed glm-cn quota via OmniRoute**: OmniRoute's connection slug for the
4
+ Z.ai (CN) upstream is `glm-cn`, not `zai-coding-cn` (a Pi provider id).
5
+ Wrong slug returned "No cached usage data", so the plain-retry fallback
6
+ showed the aggregate snapshot (e.g. R:100% W:0%) instead of the Z.ai windows.
7
+ Alias `glmcn` now maps to the correct slug; footer shows `R:99%/3H`-style
8
+ windows matching the direct Z.ai display.
9
+ - OmniRoute "reset in 2h 55m" countdowns are now converted into compact
10
+ footer labels (`/3H`), and "Unavailable" windows are skipped (previously
11
+ `0%`-style aggregates leaked in via the fallback).
12
+
1
13
  ## 0.1.30 (2026-08-22)
2
14
 
3
15
  - Router usage is now **provider-scoped**: the active router model's upstream
@@ -344,6 +344,15 @@ function routerOrigin(baseUrl: string): string {
344
344
  * Sections: "Personal quota" (per-key USD budgets: Daily/Weekly) and
345
345
  * "Provider quota" (connection session/weekly). Lines: `<Label>`,
346
346
  * `NN% left`, `⏱ reset in <countdown>`. Robust to missing/unknown blocks. */
347
+ /** Convert OmniRoute's "reset in 2h 55m" countdown into the compact footer
348
+ * label (e.g. 3H), matching the direct Z.ai display (R:99%/4H). */
349
+ function countdownToLabel(text: string): string | undefined {
350
+ const m = text.match(/(?:(\d+)\s*d)?\s*(?:(\d+)\s*h)?\s*(?:(\d+)\s*m)?/);
351
+ if (!m || (!m[1] && !m[2] && !m[3])) return undefined;
352
+ const secs = Number(m[1] || 0) * 86400 + Number(m[2] || 0) * 3600 + Number(m[3] || 0) * 60;
353
+ return secs ? formatRemainingTime(Date.now() / 1000 + secs) : undefined;
354
+ }
355
+
347
356
  export function parseOmniUsageText(text: string): {
348
357
  personalDaily?: UsageWindow;
349
358
  personalWeekly?: UsageWindow;
@@ -369,7 +378,10 @@ export function parseOmniUsageText(text: string): {
369
378
  const remaining = Number(usedMatch[1]);
370
379
  if (remaining < 0 || remaining > 100) continue;
371
380
  const window: UsageWindow = { remaining };
372
- if (resetMatch) window.resetLabel = `⏱ ${resetMatch[1].trim()}`;
381
+ if (resetMatch) {
382
+ window.resetLabel = `⏱ ${resetMatch[1].trim()}`;
383
+ window.remainingLabel = countdownToLabel(resetMatch[1]);
384
+ }
373
385
  if (inPersonal) {
374
386
  if (label.includes("daily")) out.personalDaily = window;
375
387
  else if (label.includes("weekly")) out.personalWeekly = window;
@@ -397,6 +409,10 @@ if (process.env.PI_SUB_SELF_CHECK === "1") {
397
409
  assert(rp("command-code/deepseek/deepseek-v4-flash") === "command-code", "prefix command-code");
398
410
  assert(rp("cmd/deepseek/deepseek-v4-flash") === "command-code", "alias cmd → command-code");
399
411
  assert(rp("oc/gpt-5") === "opencode-go", "alias oc → opencode-go");
412
+ // OmniRoute's connection slug is `glm-cn` (live-verified; zai-coding-cn is a
413
+ // Pi provider id, NOT an OmniRoute slug — wrong slug = no cached data).
414
+ assert(rp("glm-cn/glm-5.2") === "glm-cn", "glm-cn passes through");
415
+ assert(rp("glmcn/glm-5.2") === "glm-cn", "alias glmcn → glm-cn");
400
416
  assert(rp("zai-coding/glm-5.2") === "zai-coding", "prefix zai-coding");
401
417
  assert(rp("auto/best") === undefined, "generic auto filtered");
402
418
  assert(rp("openrouter/gpt-5") === undefined, "generic openrouter filtered");
@@ -417,6 +433,14 @@ if (process.env.PI_SUB_SELF_CHECK === "1") {
417
433
  assert(live.session?.remaining === 90, "session 90");
418
434
  assert(live.providerWeekly?.remaining === 0, "weekly 0");
419
435
  assert(live.session?.resetLabel?.includes("1h 59m"), "session reset");
436
+ // Live-verified 2026-08-22: glm-cn scoped quota — Session 99%, Weekly
437
+ // "Unavailable" (skipped, so W stays absent like the direct Z.ai footer).
438
+ const glmCn = parseOmniUsageText(
439
+ "Provider quota\nSession\n99% left\n⏱ reset in 2h 55m\n\nWeekly\nUnavailable\n⏱ reset in unknown"
440
+ );
441
+ assert(glmCn.session?.remaining === 99, "glm-cn session 99");
442
+ assert(glmCn.session?.remainingLabel === "3H", "glm-cn reset label 3H");
443
+ assert(glmCn.providerWeekly === undefined, "glm-cn weekly unavailable skipped");
420
444
  }
421
445
 
422
446
  async function fetchUsageFromPiAuth(entry: PiAuthEntry, signal?: AbortSignal): Promise<UsageApiSnapshot | undefined> {
@@ -913,7 +937,7 @@ function routerUpstreamPrefix(model: ModelLike): string | undefined {
913
937
  if (first === "cmd") return "command-code";
914
938
  if (first === "oc") return "opencode-go";
915
939
  if (first === "ds") return "deepseek";
916
- if (first === "glmcn" || first === "glm-cn") return "zai-coding-cn";
940
+ if (first === "glmcn") return "glm-cn"; // OmniRoute connection slug (not the Pi provider id zai-coding-cn)
917
941
  // Generic router aliases / upstreams without cached quota data — no provider
918
942
  // selection; the usage API returns the best snapshot instead.
919
943
  const generic = new Set(["auto", "aug", "no-think", "tllm", "combo", "openrouter", "nvidia", "felo", "pepper", "mcode", "ddgw", "veoaifree-web", "veo-free"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-sub",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "Pi extension showing subscription usage for supported model providers.",
5
5
  "type": "module",
6
6
  "license": "MIT",