@tekmidian/pai 0.1.0 → 0.2.1
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/FEATURE.md +5 -2
- package/package.json +2 -1
- package/statusline-command.sh +348 -0
package/FEATURE.md
CHANGED
|
@@ -19,7 +19,7 @@ different direction: persistent memory, session continuity, and deep Claude Code
|
|
|
19
19
|
| **Language** | Python | TypeScript (Bun) |
|
|
20
20
|
| **Primary interface** | CLI pipe (`echo "..." \| fabric -p pattern`) | MCP server + CLI (`pai`) |
|
|
21
21
|
| **Prompt templates** | Yes — 200+ community "patterns" | No (out of scope) |
|
|
22
|
-
| **YouTube transcript extraction** | Yes (built-in) |
|
|
22
|
+
| **YouTube transcript extraction** | Yes (built-in) | Yes — via [Scribe MCP](https://github.com/mnott/Scribe) |
|
|
23
23
|
| **LLM pipe-through workflow** | Yes — core feature | No |
|
|
24
24
|
| **Persistent session memory** | No | Yes — auto-indexed, 449K+ chunks |
|
|
25
25
|
| **Session registry** | No | Yes — SQLite, tracks 77+ projects |
|
|
@@ -34,6 +34,7 @@ different direction: persistent memory, session continuity, and deep Claude Code
|
|
|
34
34
|
| **Hook system** | No | Yes — pre-compact, session-stop, auto-cleanup |
|
|
35
35
|
| **Backup / restore** | No | Yes — timestamped pg_dump + registry export |
|
|
36
36
|
| **Multi-session concurrency** | n/a | Yes — daemon multiplexes Claude sessions |
|
|
37
|
+
| **Custom statusline** | No | Yes — model, MCPs, context meter, colors |
|
|
37
38
|
| **Local / private** | Yes | Yes — no cloud, no external API for core |
|
|
38
39
|
| **Docker required** | No | Only for full mode (PostgreSQL); SQLite mode needs none |
|
|
39
40
|
| **macOS / Linux** | Yes | Yes |
|
|
@@ -95,7 +96,9 @@ To be clear about scope:
|
|
|
95
96
|
- **Pipe-through LLM workflows** — Fabric's `echo "..." | fabric -p pattern` idiom is elegant
|
|
96
97
|
for processing text at the command line. PAI doesn't replicate this.
|
|
97
98
|
- **YouTube / web extraction** — Fabric can pull transcripts and content from URLs as input to
|
|
98
|
-
patterns. PAI
|
|
99
|
+
patterns. PAI covers YouTube transcription via the companion
|
|
100
|
+
[Scribe MCP](https://github.com/mnott/Scribe) server, but does not replicate Fabric's
|
|
101
|
+
web-scraping pipeline.
|
|
99
102
|
|
|
100
103
|
If you want prompt patterns and CLI pipe-through workflows, use Fabric. If you want Claude
|
|
101
104
|
Code to remember everything across sessions, use this.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekmidian/pai",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
16
|
"templates",
|
|
17
|
+
"statusline-command.sh",
|
|
17
18
|
"README.md",
|
|
18
19
|
"LICENSE",
|
|
19
20
|
"ARCHITECTURE.md",
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/opt/homebrew/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# PAI Statusline - Customizable status display for Claude Code
|
|
4
|
+
#
|
|
5
|
+
# CUSTOMIZATION:
|
|
6
|
+
# - This script sources ${PAI_DIR}/.env for API keys and configuration
|
|
7
|
+
# - Set PAI_SIMPLE_COLORS=1 in settings.json env for basic ANSI colors
|
|
8
|
+
# (fixes display issues on some terminals)
|
|
9
|
+
# - To add features requiring API keys (e.g., quotes), add keys to .env
|
|
10
|
+
# - Comment out any printf lines you don't want displayed
|
|
11
|
+
#
|
|
12
|
+
# LINES DISPLAYED:
|
|
13
|
+
# 1. Greeting: DA name, model, directory
|
|
14
|
+
# 2. MCPs: Active MCP servers (wraps on narrow terminals)
|
|
15
|
+
# 3. Context: Current session context window usage (K / 200K)
|
|
16
|
+
#
|
|
17
|
+
# ENVIRONMENT VARIABLES (set in settings.json env section):
|
|
18
|
+
# DA - Your assistant's name (default: "Assistant")
|
|
19
|
+
# DA_COLOR - Name color: purple|blue|green|cyan|yellow|red|orange
|
|
20
|
+
# PAI_SIMPLE_COLORS - Set to "1" to use basic terminal colors
|
|
21
|
+
# PAI_NO_EMOJI - Set to "1" to disable emojis (for terminals that don't render them)
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
# Source .env for API keys and custom configuration
|
|
25
|
+
claude_env="${PAI_DIR:-$HOME/.claude}/.env"
|
|
26
|
+
[ -f "$claude_env" ] && source "$claude_env"
|
|
27
|
+
|
|
28
|
+
# Read JSON input from stdin
|
|
29
|
+
input=$(cat)
|
|
30
|
+
|
|
31
|
+
# Get Digital Assistant configuration from environment
|
|
32
|
+
DA_NAME="${DA:-Assistant}" # Assistant name
|
|
33
|
+
DA_COLOR="${DA_COLOR:-purple}" # Color for the assistant name
|
|
34
|
+
|
|
35
|
+
# Extract data from JSON input
|
|
36
|
+
current_dir=$(echo "$input" | jq -r '.workspace.current_dir')
|
|
37
|
+
model_name=$(echo "$input" | jq -r '.model.display_name')
|
|
38
|
+
cc_version=$(echo "$input" | jq -r '.version // "unknown"')
|
|
39
|
+
|
|
40
|
+
# Get directory name
|
|
41
|
+
dir_name=$(basename "$current_dir")
|
|
42
|
+
|
|
43
|
+
# Read Whazaa session name from iTerm2 user variable
|
|
44
|
+
pai_session_name=""
|
|
45
|
+
if [ -n "$ITERM_SESSION_ID" ]; then
|
|
46
|
+
ITERM_UUID="${ITERM_SESSION_ID##*:}"
|
|
47
|
+
pai_session_name=$(osascript << APPLESCRIPT 2>/dev/null
|
|
48
|
+
tell application "iTerm2"
|
|
49
|
+
repeat with aWindow in windows
|
|
50
|
+
repeat with aTab in tabs of aWindow
|
|
51
|
+
repeat with aSession in sessions of aTab
|
|
52
|
+
if id of aSession is "${ITERM_UUID}" then
|
|
53
|
+
tell aSession
|
|
54
|
+
try
|
|
55
|
+
return (variable named "user.paiName")
|
|
56
|
+
on error
|
|
57
|
+
return ""
|
|
58
|
+
end try
|
|
59
|
+
end tell
|
|
60
|
+
end if
|
|
61
|
+
end repeat
|
|
62
|
+
end repeat
|
|
63
|
+
end repeat
|
|
64
|
+
return ""
|
|
65
|
+
end tell
|
|
66
|
+
APPLESCRIPT
|
|
67
|
+
)
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Build session suffix (only if different from dir_name)
|
|
71
|
+
session_suffix=""
|
|
72
|
+
if [ -n "$pai_session_name" ] && [ "$pai_session_name" != "$dir_name" ]; then
|
|
73
|
+
session_suffix=" • ${pai_session_name}"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Config directory
|
|
77
|
+
claude_dir="${PAI_DIR:-$HOME/.claude}"
|
|
78
|
+
|
|
79
|
+
# Count MCPs from all config sources (settings.json, .mcp.json, ~/.claude.json)
|
|
80
|
+
mcp_names_raw=""
|
|
81
|
+
mcps_count=0
|
|
82
|
+
|
|
83
|
+
# Helper: merge MCP names from a jq-compatible JSON file
|
|
84
|
+
_merge_mcps() {
|
|
85
|
+
local file="$1"
|
|
86
|
+
[ -f "$file" ] || return
|
|
87
|
+
local data
|
|
88
|
+
data=$(jq -r '.mcpServers | keys | join(" "), length' "$file" 2>/dev/null)
|
|
89
|
+
[ -n "$data" ] && [ "$data" != "null" ] || return
|
|
90
|
+
local names count
|
|
91
|
+
names=$(echo "$data" | head -1)
|
|
92
|
+
count=$(echo "$data" | tail -1)
|
|
93
|
+
[ -n "$names" ] || return
|
|
94
|
+
if [ -n "$mcp_names_raw" ]; then
|
|
95
|
+
mcp_names_raw="$mcp_names_raw $names"
|
|
96
|
+
else
|
|
97
|
+
mcp_names_raw="$names"
|
|
98
|
+
fi
|
|
99
|
+
mcps_count=$((mcps_count + count))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Read from all three MCP config locations
|
|
103
|
+
_merge_mcps "$claude_dir/settings.json" # legacy
|
|
104
|
+
_merge_mcps "$claude_dir/.mcp.json" # project-level
|
|
105
|
+
_merge_mcps "$HOME/.claude.json" # user-level (e.g. Coogle, DEVONthink)
|
|
106
|
+
|
|
107
|
+
# Deduplicate MCP names (preserving order)
|
|
108
|
+
if [ -n "$mcp_names_raw" ]; then
|
|
109
|
+
mcp_names_raw=$(echo "$mcp_names_raw" | tr ' ' '\n' | awk '!seen[$0]++' | tr '\n' ' ' | sed 's/ $//')
|
|
110
|
+
mcps_count=$(echo "$mcp_names_raw" | wc -w | tr -d ' ')
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Extract context window usage from Claude Code's JSON input (no JSONL parsing needed)
|
|
114
|
+
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)
|
|
116
|
+
context_used_k=$(( (context_pct * context_size / 100) / 1000 ))
|
|
117
|
+
context_max_k=$((context_size / 1000))
|
|
118
|
+
|
|
119
|
+
# Tokyo Night Storm Color Scheme
|
|
120
|
+
BACKGROUND='\033[48;2;36;40;59m'
|
|
121
|
+
BRIGHT_PURPLE='\033[38;2;187;154;247m'
|
|
122
|
+
BRIGHT_BLUE='\033[38;2;122;162;247m'
|
|
123
|
+
DARK_BLUE='\033[38;2;100;140;200m'
|
|
124
|
+
BRIGHT_GREEN='\033[38;2;158;206;106m'
|
|
125
|
+
DARK_GREEN='\033[38;2;130;170;90m'
|
|
126
|
+
BRIGHT_ORANGE='\033[38;2;255;158;100m'
|
|
127
|
+
BRIGHT_RED='\033[38;2;247;118;142m'
|
|
128
|
+
BRIGHT_CYAN='\033[38;2;125;207;255m'
|
|
129
|
+
BRIGHT_MAGENTA='\033[38;2;187;154;247m'
|
|
130
|
+
BRIGHT_YELLOW='\033[38;2;224;175;104m'
|
|
131
|
+
|
|
132
|
+
# Map DA_COLOR to actual ANSI color code
|
|
133
|
+
case "$DA_COLOR" in
|
|
134
|
+
"purple") DA_DISPLAY_COLOR='\033[38;2;147;112;219m' ;;
|
|
135
|
+
"blue") DA_DISPLAY_COLOR="$BRIGHT_BLUE" ;;
|
|
136
|
+
"green") DA_DISPLAY_COLOR="$BRIGHT_GREEN" ;;
|
|
137
|
+
"cyan") DA_DISPLAY_COLOR="$BRIGHT_CYAN" ;;
|
|
138
|
+
"magenta") DA_DISPLAY_COLOR="$BRIGHT_MAGENTA" ;;
|
|
139
|
+
"yellow") DA_DISPLAY_COLOR="$BRIGHT_YELLOW" ;;
|
|
140
|
+
"red") DA_DISPLAY_COLOR="$BRIGHT_RED" ;;
|
|
141
|
+
"orange") DA_DISPLAY_COLOR="$BRIGHT_ORANGE" ;;
|
|
142
|
+
*) DA_DISPLAY_COLOR='\033[38;2;147;112;219m' ;; # Default to purple
|
|
143
|
+
esac
|
|
144
|
+
|
|
145
|
+
# Line-specific colors
|
|
146
|
+
LINE1_PRIMARY="$BRIGHT_PURPLE"
|
|
147
|
+
LINE1_ACCENT='\033[38;2;160;130;210m'
|
|
148
|
+
MODEL_PURPLE='\033[38;2;138;99;210m'
|
|
149
|
+
|
|
150
|
+
LINE2_PRIMARY="$DARK_BLUE"
|
|
151
|
+
LINE2_ACCENT='\033[38;2;110;150;210m'
|
|
152
|
+
|
|
153
|
+
LINE3_PRIMARY="$DARK_GREEN"
|
|
154
|
+
LINE3_ACCENT='\033[38;2;140;180;100m'
|
|
155
|
+
COST_COLOR="$LINE3_ACCENT"
|
|
156
|
+
TOKENS_COLOR='\033[38;2;169;177;214m'
|
|
157
|
+
|
|
158
|
+
SEPARATOR_COLOR='\033[38;2;140;152;180m'
|
|
159
|
+
DIR_COLOR='\033[38;2;135;206;250m'
|
|
160
|
+
|
|
161
|
+
# MCP colors
|
|
162
|
+
MCP_DAEMON="$BRIGHT_BLUE"
|
|
163
|
+
MCP_STRIPE="$LINE2_ACCENT"
|
|
164
|
+
MCP_DEFAULT="$LINE2_PRIMARY"
|
|
165
|
+
|
|
166
|
+
# Reset includes explicit background clear for terminal compatibility
|
|
167
|
+
RESET='\033[0m\033[49m'
|
|
168
|
+
|
|
169
|
+
# Emoji definitions - can be disabled with PAI_NO_EMOJI=1
|
|
170
|
+
if [ "${PAI_NO_EMOJI:-0}" = "1" ]; then
|
|
171
|
+
EMOJI_WAVE=">"
|
|
172
|
+
EMOJI_BRAIN="*"
|
|
173
|
+
EMOJI_FOLDER="@"
|
|
174
|
+
EMOJI_PLUG="+"
|
|
175
|
+
EMOJI_BOOK="#"
|
|
176
|
+
EMOJI_GEM="$"
|
|
177
|
+
else
|
|
178
|
+
EMOJI_WAVE="👋"
|
|
179
|
+
EMOJI_BRAIN="🧠"
|
|
180
|
+
EMOJI_FOLDER="📁"
|
|
181
|
+
EMOJI_PLUG="🔌"
|
|
182
|
+
EMOJI_BOOK="📚"
|
|
183
|
+
EMOJI_GEM="💎"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Simple colors mode - set PAI_SIMPLE_COLORS=1 if you have terminal display issues
|
|
187
|
+
if [ "${PAI_SIMPLE_COLORS:-0}" = "1" ]; then
|
|
188
|
+
# Use basic ANSI colors instead of 24-bit RGB for terminal compatibility
|
|
189
|
+
BRIGHT_PURPLE='\033[35m'
|
|
190
|
+
BRIGHT_BLUE='\033[34m'
|
|
191
|
+
DARK_BLUE='\033[34m'
|
|
192
|
+
BRIGHT_GREEN='\033[32m'
|
|
193
|
+
DARK_GREEN='\033[32m'
|
|
194
|
+
BRIGHT_ORANGE='\033[33m'
|
|
195
|
+
BRIGHT_RED='\033[31m'
|
|
196
|
+
BRIGHT_CYAN='\033[36m'
|
|
197
|
+
BRIGHT_MAGENTA='\033[35m'
|
|
198
|
+
BRIGHT_YELLOW='\033[33m'
|
|
199
|
+
# Override derived colors
|
|
200
|
+
DA_DISPLAY_COLOR='\033[35m'
|
|
201
|
+
LINE1_PRIMARY='\033[35m'
|
|
202
|
+
LINE1_ACCENT='\033[35m'
|
|
203
|
+
MODEL_PURPLE='\033[35m'
|
|
204
|
+
LINE2_PRIMARY='\033[34m'
|
|
205
|
+
LINE2_ACCENT='\033[34m'
|
|
206
|
+
LINE3_PRIMARY='\033[32m'
|
|
207
|
+
LINE3_ACCENT='\033[32m'
|
|
208
|
+
COST_COLOR='\033[32m'
|
|
209
|
+
TOKENS_COLOR='\033[37m'
|
|
210
|
+
SEPARATOR_COLOR='\033[37m'
|
|
211
|
+
DIR_COLOR='\033[36m'
|
|
212
|
+
MCP_DAEMON='\033[34m'
|
|
213
|
+
MCP_STRIPE='\033[34m'
|
|
214
|
+
MCP_DEFAULT='\033[34m'
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# Format MCP names with terminal-width-aware wrapping
|
|
218
|
+
# Debug: log available width info (remove after testing)
|
|
219
|
+
# Terminal width for line truncation
|
|
220
|
+
# Claude Code's statusline subprocess can't detect resize (stty returns stale values).
|
|
221
|
+
# To set your width: echo 105 > ~/.claude/.statusline_width
|
|
222
|
+
# Default 80 is safe for any terminal; set higher (e.g., 105) for wide screens.
|
|
223
|
+
term_width=80
|
|
224
|
+
[ -f "${claude_dir}/.statusline_width" ] && read -r term_width < "${claude_dir}/.statusline_width" 2>/dev/null
|
|
225
|
+
[ "$term_width" -gt 0 ] 2>/dev/null || term_width=80
|
|
226
|
+
mcp_prefix_width=10 # visual width of "🔌 MCPs: " (emoji=2 + space + "MCPs: " = 10)
|
|
227
|
+
|
|
228
|
+
# Build MCP output — proactively split into two lines when there are many MCPs.
|
|
229
|
+
# No width detection needed: if total display chars > 60, split at the midpoint.
|
|
230
|
+
_mcp_display_name() {
|
|
231
|
+
case "$1" in
|
|
232
|
+
"daemon") echo "Daemon" ;;
|
|
233
|
+
"stripe") echo "Stripe" ;;
|
|
234
|
+
"httpx") echo "HTTPx" ;;
|
|
235
|
+
"brightdata") echo "BrightData" ;;
|
|
236
|
+
"naabu") echo "Naabu" ;;
|
|
237
|
+
"apify") echo "Apify" ;;
|
|
238
|
+
"content") echo "Content" ;;
|
|
239
|
+
"Ref") echo "Ref" ;;
|
|
240
|
+
"pai") echo "PAI" ;;
|
|
241
|
+
"playwright") echo "PW" ;;
|
|
242
|
+
"workspace") echo "Coogle" ;;
|
|
243
|
+
"macos_automator") echo "macOS" ;;
|
|
244
|
+
"claude_ai_Gmail") echo "Gmail" ;;
|
|
245
|
+
"claude_ai_Google_Calendar") echo "GCal" ;;
|
|
246
|
+
*) local n="$1"; echo "${n^}" ;;
|
|
247
|
+
esac
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
_mcp_formatted() {
|
|
251
|
+
local display_name="$1"
|
|
252
|
+
case "$display_name" in
|
|
253
|
+
"Daemon") printf "${MCP_DAEMON}%s${RESET}" "$display_name" ;;
|
|
254
|
+
"Stripe") printf "${MCP_STRIPE}%s${RESET}" "$display_name" ;;
|
|
255
|
+
*) printf "${MCP_DEFAULT}%s${RESET}" "$display_name" ;;
|
|
256
|
+
esac
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# Collect all display names and calculate total width
|
|
260
|
+
mcp_display_names=()
|
|
261
|
+
mcp_formatted_strs=()
|
|
262
|
+
total_display_width=$mcp_prefix_width # start with "🔌 MCPs: " prefix
|
|
263
|
+
total_mcps=0
|
|
264
|
+
|
|
265
|
+
for mcp in $mcp_names_raw; do
|
|
266
|
+
dn=$(_mcp_display_name "$mcp")
|
|
267
|
+
fm=$(_mcp_formatted "$dn")
|
|
268
|
+
mcp_display_names+=("$dn")
|
|
269
|
+
mcp_formatted_strs+=("$fm")
|
|
270
|
+
if [ $total_mcps -gt 0 ]; then
|
|
271
|
+
total_display_width=$((total_display_width + 2)) # ", "
|
|
272
|
+
fi
|
|
273
|
+
total_display_width=$((total_display_width + ${#dn}))
|
|
274
|
+
total_mcps=$((total_mcps + 1))
|
|
275
|
+
done
|
|
276
|
+
|
|
277
|
+
# Decide: one line or two lines?
|
|
278
|
+
# If total display width > 60 chars, split at the midpoint
|
|
279
|
+
mcp_line1=""
|
|
280
|
+
mcp_line2=""
|
|
281
|
+
|
|
282
|
+
if [ $total_mcps -eq 0 ]; then
|
|
283
|
+
mcp_line1="none"
|
|
284
|
+
elif [ $total_display_width -le $term_width ]; then
|
|
285
|
+
# Single line — everything fits
|
|
286
|
+
for ((i=0; i<total_mcps; i++)); do
|
|
287
|
+
if [ $i -eq 0 ]; then
|
|
288
|
+
mcp_line1="${mcp_formatted_strs[$i]}"
|
|
289
|
+
else
|
|
290
|
+
mcp_line1="${mcp_line1}${SEPARATOR_COLOR}, ${mcp_formatted_strs[$i]}"
|
|
291
|
+
fi
|
|
292
|
+
done
|
|
293
|
+
else
|
|
294
|
+
# Two lines — split at midpoint
|
|
295
|
+
split_at=$(( (total_mcps + 1) / 2 ))
|
|
296
|
+
for ((i=0; i<split_at; i++)); do
|
|
297
|
+
if [ $i -eq 0 ]; then
|
|
298
|
+
mcp_line1="${mcp_formatted_strs[$i]}"
|
|
299
|
+
else
|
|
300
|
+
mcp_line1="${mcp_line1}${SEPARATOR_COLOR}, ${mcp_formatted_strs[$i]}"
|
|
301
|
+
fi
|
|
302
|
+
done
|
|
303
|
+
for ((i=split_at; i<total_mcps; i++)); do
|
|
304
|
+
if [ $i -eq $split_at ]; then
|
|
305
|
+
mcp_line2="${mcp_formatted_strs[$i]}"
|
|
306
|
+
else
|
|
307
|
+
mcp_line2="${mcp_line2}${SEPARATOR_COLOR}, ${mcp_formatted_strs[$i]}"
|
|
308
|
+
fi
|
|
309
|
+
done
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
# Output the statusline
|
|
313
|
+
# LINE 1 - Greeting (adaptive: drop CC version when narrow, shorten further if very narrow)
|
|
314
|
+
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}"
|
|
315
|
+
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}"
|
|
316
|
+
line1_short="${EMOJI_WAVE} ${MODEL_PURPLE}${EMOJI_BRAIN} ${model_name}${RESET}${LINE1_PRIMARY} ${DIR_COLOR}${EMOJI_FOLDER} ${dir_name}${BRIGHT_CYAN}${session_suffix}${RESET}"
|
|
317
|
+
|
|
318
|
+
# Pick line 1 format based on width (plain-text lengths: full~85, medium~45, short~25)
|
|
319
|
+
if [ $term_width -ge 90 ]; then
|
|
320
|
+
printf "${line1_full}\n"
|
|
321
|
+
elif [ $term_width -ge 50 ]; then
|
|
322
|
+
printf "${line1_medium}\n"
|
|
323
|
+
else
|
|
324
|
+
printf "${line1_short}\n"
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
# LINE 2 - MCPs (with optional wrap to second line)
|
|
328
|
+
printf "${LINE2_PRIMARY}${EMOJI_PLUG} MCPs${RESET}${LINE2_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${mcp_line1}${RESET}\n"
|
|
329
|
+
if [ -n "$mcp_line2" ]; then
|
|
330
|
+
# Continuation line — indent to align with MCP names after "🔌 MCPs: "
|
|
331
|
+
printf "${LINE2_PRIMARY} ${RESET}${mcp_line2}${RESET}\n"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# LINE 3 - Context meter (from Claude Code's JSON input)
|
|
335
|
+
if [ "$context_pct" -gt 0 ] 2>/dev/null; then
|
|
336
|
+
# Color based on usage: green < 50%, yellow 50-75%, red > 75%
|
|
337
|
+
if [ $context_pct -gt 75 ]; then
|
|
338
|
+
ctx_color="$BRIGHT_RED"
|
|
339
|
+
elif [ $context_pct -gt 50 ]; then
|
|
340
|
+
ctx_color="$BRIGHT_YELLOW"
|
|
341
|
+
else
|
|
342
|
+
ctx_color="$BRIGHT_GREEN"
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
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${RESET}\n"
|
|
346
|
+
else
|
|
347
|
+
printf "${LINE3_PRIMARY}${EMOJI_GEM} Context${RESET}${LINE3_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${LINE3_ACCENT}...${RESET}\n"
|
|
348
|
+
fi
|