@tekmidian/pai 0.39.0 → 0.40.0

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 (126) hide show
  1. package/README.md +41 -0
  2. package/dist/{auto-route-BlWOWT4z.mjs → auto-route-BwzmlW3W.mjs} +2 -2
  3. package/dist/{auto-route-BlWOWT4z.mjs.map → auto-route-BwzmlW3W.mjs.map} +1 -1
  4. package/dist/{chain-CTtHligI.mjs → chain-DhVHVnmT.mjs} +263 -791
  5. package/dist/chain-DhVHVnmT.mjs.map +1 -0
  6. package/dist/cli/index.mjs +10 -8
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/cli/program.mjs +10 -8
  9. package/dist/{clusters-wlK0w41E.mjs → clusters-DRHhfli9.mjs} +1 -1
  10. package/dist/{clusters-wlK0w41E.mjs.map → clusters-DRHhfli9.mjs.map} +1 -1
  11. package/dist/{config-B64vFg14.mjs → config-D1G9IFpn.mjs} +50 -3
  12. package/dist/config-D1G9IFpn.mjs.map +1 -0
  13. package/dist/{config-C_ErGddD.mjs → config-DD52BPB-.mjs} +1 -1
  14. package/dist/config-Dl8lT4Lu.mjs +527 -0
  15. package/dist/config-Dl8lT4Lu.mjs.map +1 -0
  16. package/dist/{context-handover-cache-BpUojjsi.mjs → context-handover-cache-C6_rs7JT.mjs} +112 -24
  17. package/dist/context-handover-cache-C6_rs7JT.mjs.map +1 -0
  18. package/dist/daemon/index.mjs +12 -10
  19. package/dist/daemon/index.mjs.map +1 -1
  20. package/dist/daemon-BSL9sXxm.mjs +22 -0
  21. package/dist/{daemon-CTkN_Vn8.mjs → daemon-CpdVUnl_.mjs} +26 -26
  22. package/dist/{daemon-CTkN_Vn8.mjs.map → daemon-CpdVUnl_.mjs.map} +1 -1
  23. package/dist/daemon-mcp/index.mjs +127 -6
  24. package/dist/daemon-mcp/index.mjs.map +1 -1
  25. package/dist/detector-BLVOCiJ_.mjs +5 -0
  26. package/dist/{detector-Bwk_4Pk4.mjs → detector-smpCm7ku.mjs} +1 -1
  27. package/dist/{detector-Bwk_4Pk4.mjs.map → detector-smpCm7ku.mjs.map} +1 -1
  28. package/dist/{factory-A9x-T2Kg.mjs → factory-Bc5EyN54.mjs} +7 -7
  29. package/dist/{factory-A9x-T2Kg.mjs.map → factory-Bc5EyN54.mjs.map} +1 -1
  30. package/dist/factory-C7ua_3ik.mjs +3 -0
  31. package/dist/{providers-FYkZjn_C.mjs → fallback-CdXv-Np0.mjs} +411 -51
  32. package/dist/fallback-CdXv-Np0.mjs.map +1 -0
  33. package/dist/hooks/context-compression-hook.mjs +136 -22
  34. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  35. package/dist/hooks/post-compact-inject.mjs +98 -7
  36. package/dist/hooks/post-compact-inject.mjs.map +4 -4
  37. package/dist/hooks/route-agents-to-worker.mjs +75 -6
  38. package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
  39. package/dist/hooks/worker-proxy.mjs +75 -6
  40. package/dist/hooks/worker-proxy.mjs.map +2 -2
  41. package/dist/hooks/worker-status-line.mjs +149 -90
  42. package/dist/hooks/worker-status-line.mjs.map +4 -4
  43. package/dist/{indexer-backend-TG64CCQC.mjs → indexer-backend-rohVVKrA.mjs} +1 -1
  44. package/dist/{indexer-backend-TG64CCQC.mjs.map → indexer-backend-rohVVKrA.mjs.map} +1 -1
  45. package/dist/{ipc-client-BmypMNYk.mjs → ipc-client-C7AVpsyv.mjs} +2 -2
  46. package/dist/{ipc-client-BmypMNYk.mjs.map → ipc-client-C7AVpsyv.mjs.map} +1 -1
  47. package/dist/{kg-entity-r8duqhi9.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
  48. package/dist/{kg-entity-r8duqhi9.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
  49. package/dist/{latent-ideas-B7wq75Pt.mjs → latent-ideas-iNp5s55R.mjs} +2 -2
  50. package/dist/{latent-ideas-B7wq75Pt.mjs.map → latent-ideas-iNp5s55R.mjs.map} +1 -1
  51. package/dist/{link-boost-HkG7JWZR.mjs → link-boost-NNzADHX_.mjs} +1 -1
  52. package/dist/{link-boost-HkG7JWZR.mjs.map → link-boost-NNzADHX_.mjs.map} +1 -1
  53. package/dist/{main-resolver-DlaLOFBA.mjs → main-resolver-CM1IHbuu.mjs} +78 -75
  54. package/dist/main-resolver-CM1IHbuu.mjs.map +1 -0
  55. package/dist/main-resolver-E5WlilhM.mjs +6 -0
  56. package/dist/{neighborhood-lThN-MaQ.mjs → neighborhood-AGL7oXQ2.mjs} +1 -1
  57. package/dist/{neighborhood-lThN-MaQ.mjs.map → neighborhood-AGL7oXQ2.mjs.map} +1 -1
  58. package/dist/{note-context-b6k0mAKi.mjs → note-context-BHwYpSFf.mjs} +1 -1
  59. package/dist/{note-context-b6k0mAKi.mjs.map → note-context-BHwYpSFf.mjs.map} +1 -1
  60. package/dist/{planner-BDI7bE9B.mjs → planner-Cm3g6fWH.mjs} +5 -3
  61. package/dist/{planner-BDI7bE9B.mjs.map → planner-Cm3g6fWH.mjs.map} +1 -1
  62. package/dist/{postgres-mW1n7Vi1.mjs → postgres-Dwxe290H.mjs} +1 -1
  63. package/dist/{postgres-mW1n7Vi1.mjs.map → postgres-Dwxe290H.mjs.map} +1 -1
  64. package/dist/{program-DXBwJV7h.mjs → program-AR0qlYRg.mjs} +334 -78
  65. package/dist/program-AR0qlYRg.mjs.map +1 -0
  66. package/dist/query-feedback-CGcEiGtY.mjs +3 -0
  67. package/dist/{query-feedback-BV4CcxqS.mjs → query-feedback-DZfjI34w.mjs} +1 -1
  68. package/dist/{query-feedback-BV4CcxqS.mjs.map → query-feedback-DZfjI34w.mjs.map} +1 -1
  69. package/dist/router-CAtyVQud.mjs +3 -0
  70. package/dist/{router-DcHKnEPa.mjs → router-DHracTUC.mjs} +1 -1
  71. package/dist/{router-DcHKnEPa.mjs.map → router-DHracTUC.mjs.map} +1 -1
  72. package/dist/server-BOuAOj9b.mjs +386 -0
  73. package/dist/server-BOuAOj9b.mjs.map +1 -0
  74. package/dist/skills/Worker/SKILL.md +19 -1
  75. package/dist/{sources-kLnQsNrW.mjs → sources-ju6AA7lL.mjs} +1 -1
  76. package/dist/{sources-kLnQsNrW.mjs.map → sources-ju6AA7lL.mjs.map} +1 -1
  77. package/dist/{sqlite-BenGr3UP.mjs → sqlite-kFZeWCJ2.mjs} +1 -1
  78. package/dist/{sqlite-BenGr3UP.mjs.map → sqlite-kFZeWCJ2.mjs.map} +1 -1
  79. package/dist/{state-Ca9F_sZc.mjs → state-DH_mp5Xe.mjs} +1 -1
  80. package/dist/{state-CAeyOdfq.mjs → state-ahFAbD8b.mjs} +1 -1
  81. package/dist/{state-CAeyOdfq.mjs.map → state-ahFAbD8b.mjs.map} +1 -1
  82. package/dist/{themes-BI4GMRP9.mjs → themes-DqhNUUQk.mjs} +1 -1
  83. package/dist/{themes-BI4GMRP9.mjs.map → themes-DqhNUUQk.mjs.map} +1 -1
  84. package/dist/{tools-DGcB3o_S.mjs → tools-CMlHa9lZ.mjs} +14 -14
  85. package/dist/{tools-DGcB3o_S.mjs.map → tools-CMlHa9lZ.mjs.map} +1 -1
  86. package/dist/{tools-Bp7hj6OW.mjs → tools-COna9vZR.mjs} +1 -1
  87. package/dist/{trace-bobARFEX.mjs → trace-DTP6k4B_.mjs} +1 -1
  88. package/dist/{trace-bobARFEX.mjs.map → trace-DTP6k4B_.mjs.map} +1 -1
  89. package/dist/{vault-indexer-C3OfXTNF.mjs → vault-indexer-YMH22mLU.mjs} +1 -1
  90. package/dist/{vault-indexer-C3OfXTNF.mjs.map → vault-indexer-YMH22mLU.mjs.map} +1 -1
  91. package/dist/{work-queue-worker-R7UGIag_.mjs → work-queue-worker-B3nl8yyn.mjs} +23 -26
  92. package/dist/work-queue-worker-B3nl8yyn.mjs.map +1 -0
  93. package/dist/work-queue-worker-BM1GcAAq.mjs +14 -0
  94. package/dist/{zettelkasten-m5QPtb-L.mjs → zettelkasten-DDvKRm2V.mjs} +3 -3
  95. package/dist/{zettelkasten-m5QPtb-L.mjs.map → zettelkasten-DDvKRm2V.mjs.map} +1 -1
  96. package/docs/commands/README.md +5 -2
  97. package/docs/commands/worker.md +66 -5
  98. package/docs/images/provider-abstraction-live.png +0 -0
  99. package/docs/images/workers.png +0 -0
  100. package/docs/launcher-independence.md +70 -0
  101. package/docs/provider-abstraction.md +87 -0
  102. package/docs/provider-independence-details.md +330 -0
  103. package/docs/provider-independence.md +75 -0
  104. package/docs/worker.md +72 -11
  105. package/package.json +1 -1
  106. package/scripts/build-hooks.mjs +6 -1
  107. package/scripts/build-skill-stubs.mjs +17 -4
  108. package/src/hooks/ts/lib/context-fill.test.ts +158 -4
  109. package/src/hooks/ts/lib/context-fill.ts +102 -35
  110. package/statusline-command.sh +120 -21
  111. package/dist/chain-CTtHligI.mjs.map +0 -1
  112. package/dist/config-B64vFg14.mjs.map +0 -1
  113. package/dist/context-handover-cache-BpUojjsi.mjs.map +0 -1
  114. package/dist/daemon-CmHHmKpg.mjs +0 -20
  115. package/dist/detector-DO730Zq0.mjs +0 -5
  116. package/dist/factory-BD-np0Vd.mjs +0 -3
  117. package/dist/main-resolver-D6IImXvF.mjs +0 -4
  118. package/dist/main-resolver-DlaLOFBA.mjs.map +0 -1
  119. package/dist/program-DXBwJV7h.mjs.map +0 -1
  120. package/dist/providers-FYkZjn_C.mjs.map +0 -1
  121. package/dist/query-feedback-DSVyHtrG.mjs +0 -3
  122. package/dist/router-Bk77E7hj.mjs +0 -3
  123. package/dist/runtime-paths-rni52zHX.mjs +0 -50
  124. package/dist/runtime-paths-rni52zHX.mjs.map +0 -1
  125. package/dist/work-queue-worker-DW8lz-Oo.mjs +0 -11
  126. package/dist/work-queue-worker-R7UGIag_.mjs.map +0 -1
@@ -35,8 +35,18 @@ DA_COLOR="${DA_COLOR:-purple}" # Color for the assistant name
35
35
  # Extract data from JSON input
36
36
  current_dir=$(echo "$input" | jq -r '.workspace.current_dir')
37
37
  model_name=$(echo "$input" | jq -r '.model.display_name')
38
+ model_id=$(echo "$input" | jq -r '.model.id // .model.display_name // empty')
38
39
  cc_version=$(echo "$input" | jq -r '.version // "unknown"')
39
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.
44
+ model_base="${model_id%%\[*}"
45
+ is_glm=0
46
+ case "$model_base" in
47
+ [Gg][Ll][Mm]*) is_glm=1 ;;
48
+ esac
49
+
40
50
  # Get directory name
41
51
  dir_name=$(basename "$current_dir")
42
52
 
@@ -112,7 +122,14 @@ fi
112
122
 
113
123
  # Extract context window usage from Claude Code's JSON input (no JSONL parsing needed)
114
124
  context_pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' 2>/dev/null)
115
- context_size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000' 2>/dev/null)
125
+ # When the payload omits the window size, derive it from the model id instead
126
+ # of assuming 200k for every model: [1m] models carry a 1M window, everything
127
+ # else keeps the claude default. This value is persisted below for hooks.
128
+ default_context_size=200000
129
+ case "$model_id" in
130
+ *"[1m]") default_context_size=1000000 ;;
131
+ esac
132
+ context_size=$(echo "$input" | jq -r --argjson d "$default_context_size" '.context_window.context_window_size // $d' 2>/dev/null)
116
133
  context_used_k=$(( (context_pct * context_size / 100) / 1000 ))
117
134
  context_max_k=$((context_size / 1000))
118
135
 
@@ -125,7 +142,7 @@ if [ -n "$statusline_session_id" ]; then
125
142
  context_state_file="${TMPDIR:-/tmp}/pai-context-${statusline_session_id}.json"
126
143
  jq -n \
127
144
  --argjson used_percentage "${context_pct:-0}" \
128
- --argjson context_window_size "${context_size:-200000}" \
145
+ --argjson context_window_size "${context_size:-$default_context_size}" \
129
146
  --arg session_id "$statusline_session_id" \
130
147
  --argjson timestamp "$(date +%s000)" \
131
148
  '{used_percentage: $used_percentage, context_window_size: $context_window_size, session_id: $session_id, timestamp: $timestamp}' \
@@ -347,11 +364,22 @@ if [ -n "$mcp_line2" ]; then
347
364
  fi
348
365
 
349
366
 
350
- # Fetch OAuth usage (5-hour current + 7-day weekly) with caching
367
+ # Usage suffix: provider-aware. glm sessions read the Z.ai plan quota
368
+ # (5-hour + weekly credit windows), everything else keeps the Anthropic
369
+ # OAuth path (5-hour + 1d pace + 7-day). Both cache for usage_cache_ttl.
351
370
  usage_cache="/tmp/claude/statusline-usage-cache.json"
371
+ zai_cache="/tmp/claude/statusline-zai-cache.json"
352
372
  usage_cache_ttl=60 # seconds
353
373
  usage_suffix=""
354
374
 
375
+ # Color based on utilization: green < 50%, yellow 50-75%, red > 75%
376
+ _usage_color() {
377
+ local pct=$1
378
+ if [ "$pct" -gt 75 ] 2>/dev/null; then echo "$BRIGHT_RED"
379
+ elif [ "$pct" -gt 50 ] 2>/dev/null; then echo "$BRIGHT_YELLOW"
380
+ else echo "$BRIGHT_GREEN"; fi
381
+ }
382
+
355
383
  _fetch_usage() {
356
384
  # Try to get OAuth token from macOS Keychain
357
385
  local token=""
@@ -367,18 +395,21 @@ _fetch_usage() {
367
395
  [ -n "$response" ] && echo "$response" > "$usage_cache"
368
396
  }
369
397
 
370
- # Use cache if fresh, otherwise fetch in background
371
- if [ -f "$usage_cache" ]; then
372
- cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
373
- if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
398
+ # Use cache if fresh, otherwise fetch in background (Anthropic plan only)
399
+ if [ "$is_glm" -eq 0 ]; then
400
+ if [ -f "$usage_cache" ]; then
401
+ cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
402
+ if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
403
+ _fetch_usage &
404
+ fi
405
+ else
374
406
  _fetch_usage &
375
407
  fi
376
- else
377
- _fetch_usage &
378
408
  fi
379
409
 
380
- # Read cached usage data
381
- if [ -f "$usage_cache" ]; then
410
+ # Read cached usage data — skipped on glm sessions so Anthropic-plan numbers
411
+ # (usage line AND the advisor-mode budget file) never leak into a glm statusline
412
+ if [ "$is_glm" -eq 0 ] && [ -f "$usage_cache" ]; then
382
413
  five_hour=$(jq -r '.five_hour.utilization // 0' "$usage_cache" 2>/dev/null)
383
414
  seven_day=$(jq -r '.seven_day.utilization // 0' "$usage_cache" 2>/dev/null)
384
415
  five_reset=$(jq -r '.five_hour.resets_at // empty' "$usage_cache" 2>/dev/null)
@@ -406,14 +437,6 @@ if [ -f "$usage_cache" ]; then
406
437
  seven_reset_fmt=$([ "$seven_reset_epoch" -gt 0 ] 2>/dev/null && date -r "$seven_reset_epoch" "+%a %H:%M" 2>/dev/null || echo "")
407
438
  fi
408
439
 
409
- # Color based on utilization: green < 50%, yellow 50-75%, red > 75%
410
- _usage_color() {
411
- local pct=$1
412
- if [ "$pct" -gt 75 ] 2>/dev/null; then echo "$BRIGHT_RED"
413
- elif [ "$pct" -gt 50 ] 2>/dev/null; then echo "$BRIGHT_YELLOW"
414
- else echo "$BRIGHT_GREEN"; fi
415
- }
416
-
417
440
  five_color=$(_usage_color "$five_hour_int")
418
441
  seven_color=$(_usage_color "$seven_day_int")
419
442
 
@@ -504,6 +527,80 @@ if [ -f "$usage_cache" ]; then
504
527
  usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} ${seven_color}${seven_label}${RESET}"
505
528
  fi
506
529
 
530
+ # Z.ai plan quota (glm sessions). The monitor endpoint exposes two credit
531
+ # windows: limits[] number==5 is the 5-hour window, number==1 the weekly one
532
+ # (nextResetTime in epoch ms) — no 1d window exists on this plan, so none is
533
+ # rendered. PAI_ZAI_QUOTA_URL overrides the endpoint (kill switch / testing).
534
+ _fetch_zai_usage() {
535
+ local key="${ZAI_API_KEY:-}"
536
+ if [ -z "$key" ] && [ -f "$HOME/.config/zai/api_key" ]; then
537
+ key=$(tr -d '[:space:]' < "$HOME/.config/zai/api_key")
538
+ fi
539
+ [ -n "$key" ] || return
540
+ mkdir -p /tmp/claude
541
+ local response
542
+ response=$(curl -sf --max-time 3 \
543
+ -H "Authorization: Bearer $key" \
544
+ -H "Accept: application/json" \
545
+ "${PAI_ZAI_QUOTA_URL:-https://api.z.ai/api/monitor/usage/quota/limit}" 2>/dev/null)
546
+ # A bad key returns HTTP 200 with empty limits — only cache responses
547
+ # that actually carry quota windows, so a broken fetch is never cached.
548
+ if [ -n "$response" ] && echo "$response" | jq -e '.data.limits | length > 0' >/dev/null 2>&1; then
549
+ echo "$response" > "$zai_cache"
550
+ fi
551
+ }
552
+
553
+ if [ "$is_glm" -eq 1 ]; then
554
+ # Use cache if fresh, otherwise fetch in background
555
+ if [ -f "$zai_cache" ]; then
556
+ cache_age=$(( $(date +%s) - $(stat -f %m "$zai_cache" 2>/dev/null || echo 0) ))
557
+ if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
558
+ _fetch_zai_usage &
559
+ fi
560
+ else
561
+ _fetch_zai_usage &
562
+ fi
563
+
564
+ zai_five_pct=""
565
+ zai_seven_pct=""
566
+ zai_five_reset_ms=""
567
+ zai_seven_reset_ms=""
568
+ if [ -f "$zai_cache" ]; then
569
+ zai_five_pct=$(jq -r '.data.limits[]? | select(.number == 5) | .percentage' "$zai_cache" 2>/dev/null | head -1)
570
+ zai_seven_pct=$(jq -r '.data.limits[]? | select(.number == 1) | .percentage' "$zai_cache" 2>/dev/null | head -1)
571
+ zai_five_reset_ms=$(jq -r '.data.limits[]? | select(.number == 5) | .nextResetTime' "$zai_cache" 2>/dev/null | head -1)
572
+ zai_seven_reset_ms=$(jq -r '.data.limits[]? | select(.number == 1) | .nextResetTime' "$zai_cache" 2>/dev/null | head -1)
573
+ fi
574
+
575
+ if [ -n "$zai_five_pct" ] && [ "$zai_five_pct" != "null" ]; then
576
+ zai_five_int=$(printf "%.0f" "$zai_five_pct" 2>/dev/null || echo "?")
577
+ zai_five_reset_fmt=""
578
+ if [ -n "$zai_five_reset_ms" ] && [ "$zai_five_reset_ms" != "null" ]; then
579
+ # nextResetTime is epoch milliseconds; date -r wants seconds
580
+ zai_five_epoch=$(( zai_five_reset_ms / 1000 ))
581
+ [ "$zai_five_epoch" -gt 0 ] 2>/dev/null && zai_five_reset_fmt=$(date -r "$zai_five_epoch" "+%H:%M" 2>/dev/null || echo "")
582
+ fi
583
+ zai_five_label="zai 5h: ${zai_five_int}%%"
584
+ [ -n "$zai_five_reset_fmt" ] && zai_five_label="${zai_five_label} → ${zai_five_reset_fmt}"
585
+ usage_suffix=" ${SEPARATOR_COLOR}│${RESET} $(_usage_color "$zai_five_int")${zai_five_label}${RESET}"
586
+ if [ -n "$zai_seven_pct" ] && [ "$zai_seven_pct" != "null" ]; then
587
+ zai_seven_int=$(printf "%.0f" "$zai_seven_pct" 2>/dev/null || echo "?")
588
+ zai_seven_reset_fmt=""
589
+ if [ -n "$zai_seven_reset_ms" ] && [ "$zai_seven_reset_ms" != "null" ]; then
590
+ zai_seven_epoch=$(( zai_seven_reset_ms / 1000 ))
591
+ [ "$zai_seven_epoch" -gt 0 ] 2>/dev/null && zai_seven_reset_fmt=$(date -r "$zai_seven_epoch" "+%a %H:%M" 2>/dev/null || echo "")
592
+ fi
593
+ zai_seven_label="7d: ${zai_seven_int}%%"
594
+ [ -n "$zai_seven_reset_fmt" ] && zai_seven_label="${zai_seven_label} → ${zai_seven_reset_fmt}"
595
+ usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} $(_usage_color "$zai_seven_int")${zai_seven_label}${RESET}"
596
+ fi
597
+ else
598
+ # No key, timeout, non-200 or empty limits — show the marker instead
599
+ # of silently falling back to Anthropic-plan numbers.
600
+ usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${LINE3_ACCENT}zai 5h: ?${RESET}"
601
+ fi
602
+ fi
603
+
507
604
  # LINE 3 - Context meter + usage limits
508
605
  # Auto-compact remaining: how much context left until compaction triggers
509
606
  ac_threshold="${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:-80}"
@@ -517,7 +614,7 @@ elif [ "$ac_remaining" -le 15 ] 2>/dev/null; then
517
614
  else
518
615
  ac_color="$BRIGHT_GREEN"
519
616
  fi
520
- ac_suffix=" ${ac_color}(${ac_remaining}%%)${RESET}"
617
+ ac_suffix=" ${ac_color}(${ac_remaining}%% left)${RESET}"
521
618
 
522
619
  if [ "$context_pct" -gt 0 ] 2>/dev/null; then
523
620
  # Color based on usage: green < 50%, yellow 50-75%, red > 75%
@@ -545,7 +642,9 @@ elif command -v pai >/dev/null 2>&1; then
545
642
  worker_status_cmd="pai worker status-line"
546
643
  fi
547
644
  if [ -n "$worker_status_cmd" ]; then
548
- worker_line="$("$worker_status_cmd" "${ITERM_SESSION_ID:-}" "${PWD:-}" 2>/dev/null)"
645
+ # third arg: this session's claude id — lets the worker line claim workers
646
+ # spawned from this session's Bash tool, which carry no terminal identity
647
+ worker_line="$("$worker_status_cmd" "${ITERM_SESSION_ID:-}" "${PWD:-}" "${statusline_session_id:-}" 2>/dev/null)"
549
648
  if [ -n "$worker_line" ]; then
550
649
  printf "${LINE3_PRIMARY}🐝 ${RESET}${LINE3_ACCENT}%s${RESET}\n" "$worker_line"
551
650
  fi