feat: buddymon statusline widget
Adds lib/statusline.sh — a fast bash+jq status bar widget showing active buddy, level, session XP, and any active encounter in red. install.sh now copies the script to ~/.claude/buddymon/statusline.sh and wires it into settings.json automatically during install. /buddymon statusline subcommand documented in SKILL.md for manual install.
This commit is contained in:
parent
a9c5610914
commit
0c311b099b
3 changed files with 98 additions and 0 deletions
18
install.sh
18
install.sh
|
|
@ -278,6 +278,24 @@ if not os.path.exists(log_path):
|
||||||
print(" Created hook_debug.log")
|
print(" Created hook_debug.log")
|
||||||
PYEOF
|
PYEOF
|
||||||
|
|
||||||
|
# Copy statusline script to stable user-local path
|
||||||
|
cp "${REPO_DIR}/lib/statusline.sh" "${BUDDYMON_DIR}/statusline.sh"
|
||||||
|
chmod +x "${BUDDYMON_DIR}/statusline.sh"
|
||||||
|
ok "Installed statusline.sh → ${BUDDYMON_DIR}/statusline.sh"
|
||||||
|
|
||||||
|
# Install statusline into settings.json if not already configured
|
||||||
|
python3 << PYEOF
|
||||||
|
import json
|
||||||
|
f = '${SETTINGS_FILE}'
|
||||||
|
d = json.load(open(f))
|
||||||
|
if 'statusLine' not in d:
|
||||||
|
d['statusLine'] = {"type": "command", "command": "bash ${BUDDYMON_DIR}/statusline.sh"}
|
||||||
|
json.dump(d, open(f, 'w'), indent=2)
|
||||||
|
print(" Installed Buddymon statusline in settings.json")
|
||||||
|
else:
|
||||||
|
print(" statusLine already configured — skipped (run /buddymon statusline to install manually)")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "✓ ${PLUGIN_KEY} installed!"
|
echo "✓ ${PLUGIN_KEY} installed!"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
38
lib/statusline.sh
Normal file
38
lib/statusline.sh
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Buddymon statusline — displays active buddy + encounter in the CC status bar.
|
||||||
|
# Install: add to ~/.claude/settings.json → "statusLine" → "command"
|
||||||
|
# Or run: /buddymon statusline (installs automatically)
|
||||||
|
|
||||||
|
B="$HOME/.claude/buddymon"
|
||||||
|
|
||||||
|
# Bail fast if no state directory or no starter chosen
|
||||||
|
[[ -d "$B" ]] || exit 0
|
||||||
|
STARTER=$(jq -r '.starter_chosen // false' "$B/roster.json" 2>/dev/null)
|
||||||
|
[[ "$STARTER" == "true" ]] || exit 0
|
||||||
|
|
||||||
|
# Read state
|
||||||
|
ID=$(jq -r '.buddymon_id // ""' "$B/active.json" 2>/dev/null)
|
||||||
|
[[ -n "$ID" ]] || exit 0
|
||||||
|
|
||||||
|
LVL=$(jq -r ".owned[\"$ID\"].level // 1" "$B/roster.json" 2>/dev/null)
|
||||||
|
XP=$(jq -r '.session_xp // 0' "$B/active.json" 2>/dev/null)
|
||||||
|
|
||||||
|
ENC_JSON=$(jq -c '.active_encounter // null' "$B/encounters.json" 2>/dev/null)
|
||||||
|
ENC_DISPLAY=$(echo "$ENC_JSON" | jq -r '.display // ""' 2>/dev/null)
|
||||||
|
ENC_STRENGTH=$(echo "$ENC_JSON" | jq -r '.current_strength // 0' 2>/dev/null)
|
||||||
|
|
||||||
|
# ANSI colors
|
||||||
|
CY='\033[38;2;23;146;153m' # cyan — buddy
|
||||||
|
GR='\033[38;2;64;160;43m' # green — xp
|
||||||
|
RD='\033[38;2;203;60;51m' # red — encounter
|
||||||
|
DM='\033[38;2;120;120;120m' # dim — separators
|
||||||
|
RS='\033[0m'
|
||||||
|
|
||||||
|
printf "${CY}🐾 ${ID} Lv.${LVL}${RS}"
|
||||||
|
printf " ${DM}·${RS} ${GR}+${XP}xp${RS}"
|
||||||
|
|
||||||
|
if [[ "$ENC_JSON" != "null" ]] && [[ -n "$ENC_DISPLAY" ]]; then
|
||||||
|
printf " ${RD}⚔ ${ENC_DISPLAY} [${ENC_STRENGTH}%%]${RS}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
@ -25,6 +25,7 @@ Parse `$ARGUMENTS` (trim whitespace, lowercase the first word) and dispatch:
|
||||||
| `fight` | Fight active encounter |
|
| `fight` | Fight active encounter |
|
||||||
| `catch` | Catch active encounter |
|
| `catch` | Catch active encounter |
|
||||||
| `roster` | Full roster view |
|
| `roster` | Full roster view |
|
||||||
|
| `statusline` | Install Buddymon statusline into settings.json |
|
||||||
| `help` | Show command list |
|
| `help` | Show command list |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -279,6 +280,46 @@ Read `roster.json` → `language_affinities`. Skip this section if empty.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## `statusline` — Install Buddymon Statusline
|
||||||
|
|
||||||
|
Installs the Buddymon statusline into `~/.claude/settings.json`.
|
||||||
|
|
||||||
|
The statusline shows active buddy + level + session XP, and highlights any
|
||||||
|
active encounter in red:
|
||||||
|
|
||||||
|
```
|
||||||
|
🐾 Debuglin Lv.90 · +45xp ⚔ 💀 NullWraith [60%]
|
||||||
|
```
|
||||||
|
|
||||||
|
Run this Python to install:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import json, os, shutil
|
||||||
|
|
||||||
|
SETTINGS = os.path.expanduser("~/.claude/settings.json")
|
||||||
|
PLUGIN_ROOT = os.environ.get("CLAUDE_PLUGIN_ROOT", "")
|
||||||
|
SCRIPT = os.path.join(PLUGIN_ROOT, "lib", "statusline.sh")
|
||||||
|
|
||||||
|
settings = json.load(open(SETTINGS))
|
||||||
|
|
||||||
|
if settings.get("statusLine"):
|
||||||
|
print("⚠️ A statusLine is already configured. Replace it? (y/n)")
|
||||||
|
# ask user — if no, abort
|
||||||
|
# if yes, proceed
|
||||||
|
pass
|
||||||
|
|
||||||
|
settings["statusLine"] = {
|
||||||
|
"type": "command",
|
||||||
|
"command": f"bash {SCRIPT}",
|
||||||
|
}
|
||||||
|
json.dump(settings, open(SETTINGS, "w"), indent=2)
|
||||||
|
print(f"✅ Buddymon statusline installed. Reload Claude Code to activate.")
|
||||||
|
```
|
||||||
|
|
||||||
|
If a `statusLine` is already set, show the existing command and ask before replacing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## `help`
|
## `help`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -288,4 +329,5 @@ Read `roster.json` → `language_affinities`. Skip this section if empty.
|
||||||
/buddymon fight — fight active encounter
|
/buddymon fight — fight active encounter
|
||||||
/buddymon catch — catch active encounter
|
/buddymon catch — catch active encounter
|
||||||
/buddymon roster — view full roster
|
/buddymon roster — view full roster
|
||||||
|
/buddymon statusline — install statusline widget
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue