@tekmidian/pai 0.6.2 → 0.6.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekmidian/pai",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "PAI Knowledge OS — Personal AI Infrastructure with federated memory and project management",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -310,8 +310,8 @@ fi
310
310
 
311
311
  # Output the statusline
312
312
  # LINE 1 - Greeting (adaptive: drop CC version when narrow, shorten further if very narrow)
313
- line1_full="${EMOJI_WAVE} ${DA_DISPLAY_COLOR}\"${DA_NAME} here, ready to go...\"${RESET} ${MODEL_PURPLE}Running CC ${cc_version}${RESET}${LINE1_PRIMARY} with ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} in ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
314
- line1_medium="${EMOJI_WAVE} ${DA_DISPLAY_COLOR}\"${DA_NAME}\"${RESET}${LINE1_PRIMARY} ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} in ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
313
+ line1_full="${EMOJI_WAVE} ${DA_DISPLAY_COLOR}${DA_NAME}${RESET} ${MODEL_PURPLE}CC ${cc_version}${RESET}${LINE1_PRIMARY} ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} in ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
314
+ line1_medium="${EMOJI_WAVE} ${DA_DISPLAY_COLOR}${DA_NAME}${RESET} ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} in ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
315
315
  line1_short="${EMOJI_WAVE} ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
316
316
 
317
317
  # Pick line 1 format based on width (plain-text lengths: full~85, medium~45, short~25)
@@ -330,13 +330,125 @@ if [ -n "$mcp_line2" ]; then
330
330
  printf "${LINE2_PRIMARY} ${RESET}${mcp_line2}${RESET}\n"
331
331
  fi
332
332
 
333
- # Auto-compact indicator: detect CLAUDE_AUTOCOMPACT_PCT_OVERRIDE env var
334
- autocompact_suffix=""
335
- if [ -n "${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:-}" ]; then
336
- autocompact_suffix=" ${BRIGHT_CYAN}[auto-compact: ${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE}%%]${RESET}"
333
+
334
+ # Fetch OAuth usage (5-hour current + 7-day weekly) with caching
335
+ usage_cache="/tmp/claude/statusline-usage-cache.json"
336
+ usage_cache_ttl=60 # seconds
337
+ usage_suffix=""
338
+
339
+ _fetch_usage() {
340
+ # Try to get OAuth token from macOS Keychain
341
+ local token=""
342
+ token=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
343
+ [ -z "$token" ] && return
344
+
345
+ mkdir -p /tmp/claude
346
+ local response
347
+ response=$(curl -sf --max-time 3 \
348
+ -H "Authorization: Bearer $token" \
349
+ -H "anthropic-beta: oauth-2025-04-20" \
350
+ "https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
351
+ [ -n "$response" ] && echo "$response" > "$usage_cache"
352
+ }
353
+
354
+ # Use cache if fresh, otherwise fetch in background
355
+ if [ -f "$usage_cache" ]; then
356
+ cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
357
+ if [ "$cache_age" -gt "$usage_cache_ttl" ]; then
358
+ _fetch_usage &
359
+ fi
360
+ else
361
+ _fetch_usage &
362
+ fi
363
+
364
+ # Read cached usage data
365
+ if [ -f "$usage_cache" ]; then
366
+ five_hour=$(jq -r '.five_hour.utilization // 0' "$usage_cache" 2>/dev/null)
367
+ seven_day=$(jq -r '.seven_day.utilization // 0' "$usage_cache" 2>/dev/null)
368
+ five_reset=$(jq -r '.five_hour.resets_at // empty' "$usage_cache" 2>/dev/null)
369
+ seven_reset=$(jq -r '.seven_day.resets_at // empty' "$usage_cache" 2>/dev/null)
370
+
371
+ # Round to integers
372
+ five_hour_int=$(printf "%.0f" "$five_hour" 2>/dev/null || echo 0)
373
+ seven_day_int=$(printf "%.0f" "$seven_day" 2>/dev/null || echo 0)
374
+
375
+ # Format reset times as HH:MM (local time)
376
+ five_reset_fmt=""
377
+ seven_reset_fmt=""
378
+ seven_reset_epoch=0
379
+ if [ -n "$five_reset" ]; then
380
+ five_reset_fmt=$(date -jf "%Y-%m-%dT%H:%M:%S" "$(echo "$five_reset" | cut -c1-19)" "+%H:%M" 2>/dev/null || date -d "$five_reset" "+%H:%M" 2>/dev/null || echo "")
381
+ fi
382
+ if [ -n "$seven_reset" ]; then
383
+ seven_reset_fmt=$(date -jf "%Y-%m-%dT%H:%M:%S" "$(echo "$seven_reset" | cut -c1-19)" "+%a %H:%M" 2>/dev/null || date -d "$seven_reset" "+%a %H:%M" 2>/dev/null || echo "")
384
+ seven_reset_epoch=$(date -jf "%Y-%m-%dT%H:%M:%S" "$(echo "$seven_reset" | cut -c1-19)" "+%s" 2>/dev/null || date -d "$seven_reset" "+%s" 2>/dev/null || echo 0)
385
+ fi
386
+
387
+ # Color based on utilization: green < 50%, yellow 50-75%, red > 75%
388
+ _usage_color() {
389
+ local pct=$1
390
+ if [ "$pct" -gt 75 ] 2>/dev/null; then echo "$BRIGHT_RED"
391
+ elif [ "$pct" -gt 50 ] 2>/dev/null; then echo "$BRIGHT_YELLOW"
392
+ else echo "$BRIGHT_GREEN"; fi
393
+ }
394
+
395
+ five_color=$(_usage_color "$five_hour_int")
396
+ seven_color=$(_usage_color "$seven_day_int")
397
+
398
+ # Budget pace indicator for 7-day window
399
+ # Compare actual usage vs linear expected usage based on elapsed time
400
+ pace_dot=""
401
+ if [ "$seven_reset_epoch" -gt 0 ] 2>/dev/null; then
402
+ now_epoch=$(date +%s)
403
+ window_secs=$((7 * 86400))
404
+ remaining_secs=$((seven_reset_epoch - now_epoch))
405
+ [ "$remaining_secs" -lt 0 ] && remaining_secs=0
406
+ elapsed_secs=$((window_secs - remaining_secs))
407
+ # Expected usage if spending linearly: elapsed/total * 100
408
+ expected_pct=$(( elapsed_secs * 100 / window_secs ))
409
+ # Daily pace: actual spend per day vs budget (100/7 ≈ 14%/day)
410
+ elapsed_days_x10=$((elapsed_secs * 10 / 86400))
411
+ [ "$elapsed_days_x10" -lt 1 ] && elapsed_days_x10=1
412
+ spend_per_day=$((seven_day_int * 10 / elapsed_days_x10))
413
+ budget_per_day=14 # 100/7 ≈ 14%
414
+ # Color: green = under budget, orange = near budget, red = over budget
415
+ overspend=$((spend_per_day - budget_per_day))
416
+ if [ "$overspend" -le -3 ] 2>/dev/null; then
417
+ pace_color="$BRIGHT_GREEN" # well under budget
418
+ elif [ "$overspend" -le 2 ] 2>/dev/null; then
419
+ pace_color="$BRIGHT_ORANGE" # near budget
420
+ else
421
+ pace_color="$BRIGHT_RED" # over budget
422
+ fi
423
+ pace_dot="${pace_color}${spend_per_day}%% / ${budget_per_day}%%${RESET}"
424
+ fi
425
+
426
+ # Build usage suffix: 5h: 8% → 00:59 │ 1d: ● 29% / 36% │ 7d: 29% → Fr. 08:00
427
+ five_label="5h: ${five_hour_int}%%"
428
+ [ -n "$five_reset_fmt" ] && five_label="${five_label} → ${five_reset_fmt}"
429
+ seven_label="7d: ${seven_day_int}%%"
430
+ [ -n "$seven_reset_fmt" ] && seven_label="${seven_label} → ${seven_reset_fmt}"
431
+
432
+ usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${five_color}${five_label}${RESET}"
433
+ [ -n "$pace_dot" ] && usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} ${LINE3_PRIMARY}1d:${RESET} ${pace_dot}"
434
+ usage_suffix="${usage_suffix} ${SEPARATOR_COLOR}│${RESET} ${seven_color}${seven_label}${RESET}"
435
+ fi
436
+
437
+ # LINE 3 - Context meter + usage limits
438
+ # Auto-compact remaining: how much context left until compaction triggers
439
+ ac_threshold="${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:-80}"
440
+ ac_remaining=$((ac_threshold - context_pct))
441
+ [ "$ac_remaining" -lt 0 ] && ac_remaining=0
442
+ # Color the remaining %: red ≤5, yellow ≤15, green otherwise
443
+ if [ "$ac_remaining" -le 5 ] 2>/dev/null; then
444
+ ac_color="$BRIGHT_RED"
445
+ elif [ "$ac_remaining" -le 15 ] 2>/dev/null; then
446
+ ac_color="$BRIGHT_YELLOW"
447
+ else
448
+ ac_color="$BRIGHT_GREEN"
337
449
  fi
450
+ ac_suffix=" ${ac_color}(${ac_remaining}%%)${RESET}"
338
451
 
339
- # LINE 3 - Context meter (from Claude Code's JSON input)
340
452
  if [ "$context_pct" -gt 0 ] 2>/dev/null; then
341
453
  # Color based on usage: green < 50%, yellow 50-75%, red > 75%
342
454
  if [ $context_pct -gt 75 ]; then
@@ -347,7 +459,7 @@ if [ "$context_pct" -gt 0 ] 2>/dev/null; then
347
459
  ctx_color="$BRIGHT_GREEN"
348
460
  fi
349
461
 
350
- printf "${LINE3_PRIMARY}${EMOJI_GEM} Context${RESET}${LINE3_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${ctx_color}${context_used_k}K${RESET}${LINE3_PRIMARY} / ${context_max_k}K${autocompact_suffix}${RESET}\n"
462
+ printf "${LINE3_PRIMARY}${EMOJI_GEM} Context${RESET}${LINE3_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${ctx_color}${context_used_k}K${RESET}${LINE3_PRIMARY} / ${context_max_k}K${ac_suffix}${usage_suffix}${RESET}\n"
351
463
  else
352
- printf "${LINE3_PRIMARY}${EMOJI_GEM} Context${RESET}${LINE3_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${LINE3_ACCENT}...${autocompact_suffix}${RESET}\n"
464
+ printf "${LINE3_PRIMARY}${EMOJI_GEM} Context${RESET}${LINE3_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${LINE3_ACCENT}...${ac_suffix}${usage_suffix}${RESET}\n"
353
465
  fi