@tekmidian/pai 0.42.1 → 0.42.3

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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/chain-B-DbR82m.mjs +164 -0
  3. package/dist/chain-B-DbR82m.mjs.map +1 -0
  4. package/dist/cli/index.mjs +8 -8
  5. package/dist/cli/program.mjs +8 -8
  6. package/dist/{config-Bi_F6lXf.mjs → config-_lQI_W08.mjs} +87 -3
  7. package/dist/config-_lQI_W08.mjs.map +1 -0
  8. package/dist/{context-handover-cache--bm6Siim.mjs → context-handover-cache-pNFdBNrU.mjs} +3 -3
  9. package/dist/{context-handover-cache--bm6Siim.mjs.map → context-handover-cache-pNFdBNrU.mjs.map} +1 -1
  10. package/dist/daemon/index.mjs +7 -7
  11. package/dist/{daemon-BOAPyL_b.mjs → daemon-Awt_3UJp.mjs} +7 -7
  12. package/dist/{daemon-DvXih78C.mjs → daemon-Dq8A1uDF.mjs} +587 -368
  13. package/dist/daemon-Dq8A1uDF.mjs.map +1 -0
  14. package/dist/daemon-mcp/index.mjs +5 -5
  15. package/dist/{fallback-8bzmg6No.mjs → fallback-vQPI1qxt.mjs} +14 -12
  16. package/dist/fallback-vQPI1qxt.mjs.map +1 -0
  17. package/dist/hooks/mcp-deferred-gate.mjs +286 -0
  18. package/dist/hooks/mcp-deferred-gate.mjs.map +7 -0
  19. package/dist/hooks/mcp-deferred-reminder.mjs +54 -0
  20. package/dist/hooks/mcp-deferred-reminder.mjs.map +7 -0
  21. package/dist/hooks/route-agents-to-worker.mjs +65 -2
  22. package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
  23. package/dist/hooks/worker-proxy.mjs +64 -1
  24. package/dist/hooks/worker-proxy.mjs.map +2 -2
  25. package/dist/hooks/worker-status-line.mjs +64 -1
  26. package/dist/hooks/worker-status-line.mjs.map +2 -2
  27. package/dist/hooks/worker-supervision.mjs +64 -1
  28. package/dist/hooks/worker-supervision.mjs.map +2 -2
  29. package/dist/{main-resolver-CqppP_Bw.mjs → main-resolver-BAfOMppW.mjs} +2 -2
  30. package/dist/{main-resolver-Dip2VLB5.mjs → main-resolver-DnkxPYkr.mjs} +111 -16
  31. package/dist/main-resolver-DnkxPYkr.mjs.map +1 -0
  32. package/dist/{planner-ogy-Zy4O.mjs → planner-BfEGcEs1.mjs} +5 -5
  33. package/dist/{planner-ogy-Zy4O.mjs.map → planner-BfEGcEs1.mjs.map} +1 -1
  34. package/dist/{program-B7N5OIJR.mjs → program-BDmeZP-v.mjs} +17 -11
  35. package/dist/{program-B7N5OIJR.mjs.map → program-BDmeZP-v.mjs.map} +1 -1
  36. package/dist/{chain-DsvSHnO9.mjs → run-CGXbhf2k.mjs} +359 -163
  37. package/dist/run-CGXbhf2k.mjs.map +1 -0
  38. package/dist/{server-DvN-IFIV.mjs → server-D4vAieF4.mjs} +25 -6
  39. package/dist/server-D4vAieF4.mjs.map +1 -0
  40. package/dist/{state-BTa10SOM.mjs → state-BRdB-Bf1.mjs} +7 -2
  41. package/dist/state-BRdB-Bf1.mjs.map +1 -0
  42. package/dist/state-CY6I-Hnc.mjs +3 -0
  43. package/dist/{work-queue-worker-19r0cpH4.mjs → work-queue-worker-AEmfVE0F.mjs} +5 -5
  44. package/dist/{work-queue-worker-DXh_FnT5.mjs → work-queue-worker-DIT-VLSh.mjs} +3 -3
  45. package/dist/{work-queue-worker-DXh_FnT5.mjs.map → work-queue-worker-DIT-VLSh.mjs.map} +1 -1
  46. package/docs/cache-keepalive.md +82 -0
  47. package/docs/commands/worker.md +1 -0
  48. package/docs/provider-abstraction.md +52 -2
  49. package/package.json +1 -1
  50. package/plugins/core/hooks/hooks.json +12 -0
  51. package/src/hooks/ts/lib/mcp-deferred-gate.test.ts +258 -0
  52. package/src/hooks/ts/lib/mcp-deferred-gate.ts +261 -0
  53. package/src/hooks/ts/lib/mcp-deferred-reminder.test.ts +90 -0
  54. package/src/hooks/ts/lib/mcp-deferred-reminder.ts +66 -0
  55. package/src/hooks/ts/pre-tool-use/mcp-deferred-gate.ts +126 -0
  56. package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +6 -2
  57. package/src/hooks/ts/session-start/mcp-deferred-reminder.ts +52 -0
  58. package/statusline-command.sh +149 -72
  59. package/dist/chain-DsvSHnO9.mjs.map +0 -1
  60. package/dist/config-Bi_F6lXf.mjs.map +0 -1
  61. package/dist/daemon-DvXih78C.mjs.map +0 -1
  62. package/dist/fallback-8bzmg6No.mjs.map +0 -1
  63. package/dist/main-resolver-Dip2VLB5.mjs.map +0 -1
  64. package/dist/scope-CfYnjy5R.mjs +0 -360
  65. package/dist/scope-CfYnjy5R.mjs.map +0 -1
  66. package/dist/server-DvN-IFIV.mjs.map +0 -1
  67. package/dist/state-BTa10SOM.mjs.map +0 -1
  68. package/dist/state-RXepvbnO.mjs +0 -3
@@ -38,14 +38,24 @@ model_name=$(echo "$input" | jq -r '.model.display_name')
38
38
  model_id=$(echo "$input" | jq -r '.model.id // .model.display_name // empty')
39
39
  cc_version=$(echo "$input" | jq -r '.version // "unknown"')
40
40
 
41
- # Provider detection: strip any [...] suffix (e.g. the [1m] context marker)
42
- # so "glm-5.3[1m]" is recognized as a glm model. glm sessions read their plan
43
- # usage from Z.ai, everything else keeps the Anthropic OAuth path.
41
+ # Provider detection: which worker provider is this session running on? The
42
+ # answer comes from the PAI config, not from model-name prefixes — a session
43
+ # belongs to the provider that lists its model id under workers.providers.
44
+ # Any [...] suffix (e.g. the [1m] context marker) is stripped on both sides,
45
+ # so a session on "glm-5.3[1m]" matches a configured "glm-5.3" and vice versa.
46
+ # No config, no jq, unreadable JSON or no match => anthropic, silently.
47
+ pai_config="${PAI_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/pai/config.json}"
44
48
  model_base="${model_id%%\[*}"
45
- is_glm=0
46
- case "$model_base" in
47
- [Gg][Ll][Mm]*) is_glm=1 ;;
48
- esac
49
+ session_provider=anthropic
50
+ if [ -n "$model_base" ] && [ -f "$pai_config" ] && command -v jq >/dev/null 2>&1; then
51
+ _matched_provider=$(jq -r --arg mb "$model_base" '
52
+ (.workers.providers // {}) | to_entries[] as $p
53
+ | (($p.value.models // {}) | to_entries[]) as $m
54
+ | ($m.value | tostring) as $v
55
+ | select($v == $mb or ($v | split("[")[0]) == $mb)
56
+ | $p.key' "$pai_config" 2>/dev/null | head -1)
57
+ [ -n "$_matched_provider" ] && session_provider="$_matched_provider"
58
+ fi
49
59
 
50
60
  # Get directory name
51
61
  dir_name=$(basename "$current_dir")
@@ -62,7 +72,9 @@ tell application "iTerm2"
62
72
  if id of aSession is "${ITERM_UUID}" then
63
73
  tell aSession
64
74
  try
65
- return (variable named "user.paiName")
75
+ set v to (variable named "user.paiName")
76
+ if v is missing value then return ""
77
+ return v
66
78
  on error
67
79
  return ""
68
80
  end try
@@ -77,6 +89,10 @@ APPLESCRIPT
77
89
  )
78
90
  fi
79
91
 
92
+ # Defence in depth: if the osascript text differs by version, iTerm2's unset
93
+ # variable can still surface as the literal "missing value" — normalise here.
94
+ [ "$pai_session_name" = "missing value" ] && pai_session_name=""
95
+
80
96
  # Build session suffix (only if different from dir_name)
81
97
  session_suffix=""
82
98
  if [ -n "$pai_session_name" ] && [ "$pai_session_name" != "$dir_name" ]; then
@@ -356,11 +372,12 @@ fi
356
372
  printf "${LINE2_PRIMARY}${EMOJI_PLUG} MCPs${RESET}${LINE2_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${mcp_line1}${RESET}\n"
357
373
 
358
374
 
359
- # Usage suffix: provider-aware. glm sessions read the Z.ai plan quota
360
- # (5-hour + weekly credit windows), everything else keeps the Anthropic
361
- # OAuth path (5-hour + 1d pace + 7-day). Both cache for usage_cache_ttl.
375
+ # Usage suffix: provider-aware. The built-in anthropic provider reads the
376
+ # Claude Code OAuth usage endpoint (5-hour + 1d pace + 7-day); every other
377
+ # provider is rendered from its own `usage` block in the PAI config (see
378
+ # docs/provider-abstraction.md) — endpoint, auth header and per-window jq
379
+ # expressions are config, not code. Both paths cache for usage_cache_ttl.
362
380
  usage_cache="/tmp/claude/statusline-usage-cache.json"
363
- zai_cache="/tmp/claude/statusline-zai-cache.json"
364
381
  usage_cache_ttl=60 # seconds
365
382
  usage_suffix=""
366
383
 
@@ -388,7 +405,7 @@ _fetch_usage() {
388
405
  }
389
406
 
390
407
  # Use cache if fresh, otherwise fetch in background (Anthropic plan only)
391
- if [ "$is_glm" -eq 0 ]; then
408
+ if [ "$session_provider" = "anthropic" ]; then
392
409
  if [ -f "$usage_cache" ]; then
393
410
  cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
394
411
  if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
@@ -399,9 +416,10 @@ if [ "$is_glm" -eq 0 ]; then
399
416
  fi
400
417
  fi
401
418
 
402
- # Read cached usage data — skipped on glm sessions so Anthropic-plan numbers
403
- # (usage line AND the advisor-mode budget file) never leak into a glm statusline
404
- if [ "$is_glm" -eq 0 ] && [ -f "$usage_cache" ]; then
419
+ # Read cached usage data — skipped on non-anthropic sessions so
420
+ # Anthropic-plan numbers (usage line AND the advisor-mode budget file)
421
+ # never leak into a glm or kimi statusline
422
+ if [ "$session_provider" = "anthropic" ] && [ -f "$usage_cache" ]; then
405
423
  five_hour=$(jq -r '.five_hour.utilization // 0' "$usage_cache" 2>/dev/null)
406
424
  seven_day=$(jq -r '.seven_day.utilization // 0' "$usage_cache" 2>/dev/null)
407
425
  five_reset=$(jq -r '.five_hour.resets_at // empty' "$usage_cache" 2>/dev/null)
@@ -519,77 +537,136 @@ if [ "$is_glm" -eq 0 ] && [ -f "$usage_cache" ]; then
519
537
  usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} ${seven_color}${seven_label}${RESET}"
520
538
  fi
521
539
 
522
- # Z.ai plan quota (glm sessions). The monitor endpoint exposes two credit
523
- # windows: limits[] number==5 is the 5-hour window, number==1 the weekly one
524
- # (nextResetTime in epoch ms) — no 1d window exists on this plan, so none is
525
- # rendered. PAI_ZAI_QUOTA_URL overrides the endpoint (kill switch / testing).
526
- _fetch_zai_usage() {
527
- local key="${ZAI_API_KEY:-}"
528
- if [ -z "$key" ] && [ -f "$HOME/.config/zai/api_key" ]; then
529
- key=$(tr -d '[:space:]' < "$HOME/.config/zai/api_key")
540
+ # Plan quota for a configured (non-anthropic) provider, driven entirely by
541
+ # its `usage` block: a JSON GET endpoint plus one jq expression per window.
542
+ # Fetches in the background into a per-provider cache, exactly as the OAuth
543
+ # path above does, and never blocks the status line on the network.
544
+ #
545
+ # Args: url, auth-header template, key file, cache path, probe expression.
546
+ # The probe is the first window's percent expression: a provider that answers
547
+ # HTTP 200 with an empty body (a rejected key often does) would otherwise be
548
+ # cached as a valid "no windows" reading, so a response that yields no number
549
+ # for it is dropped rather than stored.
550
+ _fetch_provider_usage() {
551
+ local url="$1" auth="$2" keyfile="$3" cache="$4" probe="$5"
552
+ local key=""
553
+ if [ -n "$keyfile" ] && [ -f "$keyfile" ]; then
554
+ key=$(tr -d '[:space:]' < "$keyfile")
530
555
  fi
531
556
  [ -n "$key" ] || return
557
+ # "Authorization: Bearer" (has a space) → "Authorization: Bearer <key>";
558
+ # a single token like "x-api-key" → "x-api-key: <key>".
559
+ local header
560
+ if [ "${auth#* }" != "$auth" ]; then
561
+ header="${auth} ${key}"
562
+ else
563
+ header="${auth}: ${key}"
564
+ fi
532
565
  mkdir -p /tmp/claude
533
566
  local response
534
567
  response=$(curl -sf --max-time 3 \
535
- -H "Authorization: Bearer $key" \
568
+ -H "$header" \
536
569
  -H "Accept: application/json" \
537
- "${PAI_ZAI_QUOTA_URL:-https://api.z.ai/api/monitor/usage/quota/limit}" 2>/dev/null)
538
- # A bad key returns HTTP 200 with empty limits — only cache responses
539
- # that actually carry quota windows, so a broken fetch is never cached.
540
- if [ -n "$response" ] && echo "$response" | jq -e '.data.limits | length > 0' >/dev/null 2>&1; then
541
- echo "$response" > "$zai_cache"
570
+ "$url" 2>/dev/null)
571
+ [ -n "$response" ] || return
572
+ if [ -n "$probe" ]; then
573
+ printf '%s' "$response" | jq -e "($probe) | numbers" >/dev/null 2>&1 || return
542
574
  fi
575
+ printf '%s' "$response" > "$cache"
543
576
  }
544
577
 
545
- if [ "$is_glm" -eq 1 ]; then
546
- # Use cache if fresh, otherwise fetch in background
547
- if [ -f "$zai_cache" ]; then
548
- cache_age=$(( $(date +%s) - $(stat -f %m "$zai_cache" 2>/dev/null || echo 0) ))
549
- if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
550
- _fetch_zai_usage &
551
- fi
552
- else
553
- _fetch_zai_usage &
578
+ # Usage rendering for a configured provider. anthropic has already been
579
+ # rendered from the OAuth cache above; everything else is rendered here from
580
+ # its usage block, or shows "<provider> usage n/a" when it has none.
581
+ if [ "$session_provider" != "anthropic" ]; then
582
+ provider_usage=""
583
+ provider_keyfile=""
584
+ if [ -f "$pai_config" ] && command -v jq >/dev/null 2>&1; then
585
+ provider_usage=$(jq -c --arg p "$session_provider" '.workers.providers[$p].usage // empty' "$pai_config" 2>/dev/null)
586
+ provider_keyfile=$(jq -r --arg p "$session_provider" '.workers.providers[$p].keyFile // empty' "$pai_config" 2>/dev/null)
587
+ case "$provider_keyfile" in "~/"*) provider_keyfile="$HOME/${provider_keyfile#\~/}" ;; esac
554
588
  fi
555
589
 
556
- zai_five_pct=""
557
- zai_seven_pct=""
558
- zai_five_reset_ms=""
559
- zai_seven_reset_ms=""
560
- if [ -f "$zai_cache" ]; then
561
- zai_five_pct=$(jq -r '.data.limits[]? | select(.number == 5) | .percentage' "$zai_cache" 2>/dev/null | head -1)
562
- zai_seven_pct=$(jq -r '.data.limits[]? | select(.number == 1) | .percentage' "$zai_cache" 2>/dev/null | head -1)
563
- zai_five_reset_ms=$(jq -r '.data.limits[]? | select(.number == 5) | .nextResetTime' "$zai_cache" 2>/dev/null | head -1)
564
- zai_seven_reset_ms=$(jq -r '.data.limits[]? | select(.number == 1) | .nextResetTime' "$zai_cache" 2>/dev/null | head -1)
565
- fi
590
+ if [ -n "$provider_usage" ]; then
591
+ usage_label=$(printf '%s' "$provider_usage" | jq -r --arg p "$session_provider" '.label // $p')
592
+ usage_url=$(printf '%s' "$provider_usage" | jq -r '.url // empty')
593
+ usage_auth=$(printf '%s' "$provider_usage" | jq -r '.authHeader // "Authorization: Bearer"')
594
+ usage_ttl=$(printf '%s' "$provider_usage" | jq -r '.ttlSeconds // empty')
595
+ [ "$usage_ttl" -gt 0 ] 2>/dev/null || usage_ttl="$usage_cache_ttl"
596
+ provider_cache="/tmp/claude/statusline-usage-${session_provider}.json"
597
+ usage_probe=$(printf '%s' "$provider_usage" | jq -r '.windows[0].percent // empty')
598
+
599
+ # Use cache if fresh, otherwise refresh in the background
600
+ if [ -n "$usage_url" ]; then
601
+ if [ -f "$provider_cache" ]; then
602
+ cache_age=$(( $(date +%s) - $(stat -f %m "$provider_cache" 2>/dev/null || echo 0) ))
603
+ if [ "$cache_age" -gt "$usage_ttl" ]; then
604
+ _fetch_provider_usage "$usage_url" "$usage_auth" "$provider_keyfile" "$provider_cache" "$usage_probe" &
605
+ fi
606
+ else
607
+ _fetch_provider_usage "$usage_url" "$usage_auth" "$provider_keyfile" "$provider_cache" "$usage_probe" &
608
+ fi
609
+ fi
566
610
 
567
- if [ -n "$zai_five_pct" ] && [ "$zai_five_pct" != "null" ]; then
568
- zai_five_int=$(printf "%.0f" "$zai_five_pct" 2>/dev/null || echo "?")
569
- zai_five_reset_fmt=""
570
- if [ -n "$zai_five_reset_ms" ] && [ "$zai_five_reset_ms" != "null" ]; then
571
- # nextResetTime is epoch milliseconds; date -r wants seconds
572
- zai_five_epoch=$(( zai_five_reset_ms / 1000 ))
573
- [ "$zai_five_epoch" -gt 0 ] 2>/dev/null && zai_five_reset_fmt=$(date -r "$zai_five_epoch" "+%H:%M" 2>/dev/null || echo "")
611
+ provider_suffix=""
612
+ if [ -f "$provider_cache" ]; then
613
+ window_count=$(printf '%s' "$provider_usage" | jq -r '.windows | length' 2>/dev/null || echo 0)
614
+ window_i=0
615
+ while [ "$window_i" -lt "$window_count" ] 2>/dev/null; do
616
+ w_name=$(printf '%s' "$provider_usage" | jq -r --argjson i "$window_i" '.windows[$i].name // empty')
617
+ w_pct_expr=$(printf '%s' "$provider_usage" | jq -r --argjson i "$window_i" '.windows[$i].percent // empty')
618
+ w_reset_expr=$(printf '%s' "$provider_usage" | jq -r --argjson i "$window_i" '.windows[$i].resetAt // empty')
619
+ w_reset_unit=$(printf '%s' "$provider_usage" | jq -r --argjson i "$window_i" '.windows[$i].resetUnit // "ms"')
620
+ window_i=$(( window_i + 1 ))
621
+
622
+ w_pct=""
623
+ [ -n "$w_pct_expr" ] && w_pct=$(jq -r "($w_pct_expr) // empty" "$provider_cache" 2>/dev/null | head -1)
624
+ [ -n "$w_pct" ] && [ "$w_pct" != "null" ] || continue
625
+ w_pct_int=$(printf "%.0f" "$w_pct" 2>/dev/null || echo "?")
626
+
627
+ w_reset_fmt=""
628
+ if [ -n "$w_reset_expr" ]; then
629
+ w_reset=$(jq -r "($w_reset_expr) // empty" "$provider_cache" 2>/dev/null | head -1)
630
+ w_epoch=0
631
+ case "$w_reset_unit" in
632
+ iso)
633
+ [ -n "$w_reset" ] && w_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "$(printf '%s' "$w_reset" | cut -c1-19)" "+%s" 2>/dev/null || date -d "$w_reset" "+%s" 2>/dev/null || echo 0)
634
+ ;;
635
+ s)
636
+ case "$w_reset" in ''|*[!0-9.]*) ;; *) w_epoch="${w_reset%%.*}" ;; esac
637
+ ;;
638
+ *)
639
+ # epoch milliseconds (the default); date -r wants seconds
640
+ case "$w_reset" in ''|*[!0-9.]*) ;; *) w_epoch=$(( ${w_reset%%.*} / 1000 )) ;; esac
641
+ ;;
642
+ esac
643
+ if [ "$w_epoch" -gt 0 ] 2>/dev/null; then
644
+ # Within the next 24h the weekday carries no information;
645
+ # beyond it, the bare time would be ambiguous.
646
+ if [ $(( w_epoch - $(date +%s) )) -lt 86400 ]; then
647
+ w_reset_fmt=$(date -r "$w_epoch" "+%H:%M" 2>/dev/null || echo "")
648
+ else
649
+ w_reset_fmt=$(date -r "$w_epoch" "+%a %H:%M" 2>/dev/null || echo "")
650
+ fi
651
+ fi
652
+ fi
653
+
654
+ w_label="${usage_label} ${w_name}: ${w_pct_int}%%"
655
+ [ -n "$w_reset_fmt" ] && w_label="${w_label} → ${w_reset_fmt}"
656
+ provider_suffix="${provider_suffix} ${SEPARATOR_COLOR}│${RESET} $(_usage_color "$w_pct_int")${w_label}${RESET}"
657
+ done
574
658
  fi
575
- zai_five_label="zai 5h: ${zai_five_int}%%"
576
- [ -n "$zai_five_reset_fmt" ] && zai_five_label="${zai_five_label} → ${zai_five_reset_fmt}"
577
- usage_suffix=" ${SEPARATOR_COLOR}│${RESET} $(_usage_color "$zai_five_int")${zai_five_label}${RESET}"
578
- if [ -n "$zai_seven_pct" ] && [ "$zai_seven_pct" != "null" ]; then
579
- zai_seven_int=$(printf "%.0f" "$zai_seven_pct" 2>/dev/null || echo "?")
580
- zai_seven_reset_fmt=""
581
- if [ -n "$zai_seven_reset_ms" ] && [ "$zai_seven_reset_ms" != "null" ]; then
582
- zai_seven_epoch=$(( zai_seven_reset_ms / 1000 ))
583
- [ "$zai_seven_epoch" -gt 0 ] 2>/dev/null && zai_seven_reset_fmt=$(date -r "$zai_seven_epoch" "+%a %H:%M" 2>/dev/null || echo "")
584
- fi
585
- zai_seven_label="7d: ${zai_seven_int}%%"
586
- [ -n "$zai_seven_reset_fmt" ] && zai_seven_label="${zai_seven_label} → ${zai_seven_reset_fmt}"
587
- usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} $(_usage_color "$zai_seven_int")${zai_seven_label}${RESET}"
659
+
660
+ if [ -n "$provider_suffix" ]; then
661
+ usage_suffix="$provider_suffix"
662
+ else
663
+ # No key, timeout, non-200 or an unusable response — show the
664
+ # marker instead of silently falling back to Anthropic numbers.
665
+ usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${LINE3_ACCENT}${usage_label} usage ?${RESET}"
588
666
  fi
589
667
  else
590
- # No key, timeout, non-200 or empty limits — show the marker instead
591
- # of silently falling back to Anthropic-plan numbers.
592
- usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${LINE3_ACCENT}zai 5h: ?${RESET}"
668
+ # A provider without a usage block has no quota endpoint to read.
669
+ usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${LINE3_ACCENT}${session_provider} usage n/a${RESET}"
593
670
  fi
594
671
  fi
595
672