claude
18
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/.claude-plugin/marketplace.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "claude-pulse",
|
||||
"owner": {
|
||||
"name": "PigeonDroid"
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Live usage status bar for Claude Code — session limits, weekly usage, lines changed, widget priorities, 10 themes, and zero API calls"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "claude-pulse",
|
||||
"source": "./",
|
||||
"description": "Real-time usage monitor with 20+ widgets, priority ordering, +N/-N code changes, 10 themes, shimmer animations, and zero API calls for usage data",
|
||||
"version": "3.0.0",
|
||||
"homepage": "https://github.com/NoobyGains/claude-pulse"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/.claude-plugin/plugin.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "claude-pulse",
|
||||
"description": "Live usage status bar for Claude Code — session limits, weekly usage, lines changed, 10 themes, widget priorities, shimmer animations, and zero API calls",
|
||||
"version": "3.0.0",
|
||||
"author": {
|
||||
"name": "PigeonDroid"
|
||||
},
|
||||
"homepage": "https://github.com/NoobyGains/claude-pulse",
|
||||
"repository": "https://github.com/NoobyGains/claude-pulse",
|
||||
"license": "MIT",
|
||||
"keywords": ["status", "usage", "themes", "status-bar", "monitoring", "pulse", "widgets"],
|
||||
"commands": "./commands/"
|
||||
}
|
||||
1
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
buy_me_a_coffee: noobygains
|
||||
3
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.env
|
||||
26
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/LICENSE
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
Source Available License
|
||||
|
||||
Copyright (c) 2026 PigeonDroid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to use
|
||||
and modify the Software for personal or internal purposes, subject to the
|
||||
following conditions:
|
||||
|
||||
1. The Software may NOT be redistributed, published, sublicensed, or shared
|
||||
in any form — whether modified or unmodified — without prior written
|
||||
permission from the copyright holder.
|
||||
|
||||
2. The Software may NOT be sold, resold, or included in any product or
|
||||
service offered for sale.
|
||||
|
||||
3. This license notice and the above copyright notice shall be included in
|
||||
all copies or substantial portions of the Software retained by the user.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
267
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/README.md
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
<p align="center">
|
||||
<img src="assets/logo.svg" alt="claude-pulse logo" width="600" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Real-time usage monitor for Claude Code — session limits, weekly limits, cost tracking, peak hours, and 10 themes with animations. All in your status bar.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/NoobyGains/claude-pulse/stargazers"><img src="https://img.shields.io/github/stars/NoobyGains/claude-pulse?style=social" alt="GitHub Stars" /></a>
|
||||
<img src="https://img.shields.io/github/v/tag/NoobyGains/claude-pulse?label=version&color=blue" alt="Version" />
|
||||
<img src="https://img.shields.io/badge/python-3.6+-3776AB?logo=python&logoColor=white" alt="Python 3.6+" />
|
||||
<img src="https://img.shields.io/badge/dependencies-zero-brightgreen" alt="Zero Dependencies" />
|
||||
<img src="https://img.shields.io/badge/Claude%20Code-v2.1.80+-7C3AED?logo=anthropic&logoColor=white" alt="Claude Code v2.1.80+" />
|
||||
<img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey" alt="Platform" />
|
||||
<a href="https://github.com/NoobyGains/claude-pulse/blob/main/LICENSE"><img src="https://img.shields.io/github/license/NoobyGains/claude-pulse?color=green" alt="License" /></a>
|
||||
<a href="https://buymeacoffee.com/noobygains"><img src="https://img.shields.io/badge/buy%20me%20a%20coffee-donate-FFDD00?logo=buymeacoffee&logoColor=black" alt="Buy Me A Coffee" /></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## What is this?
|
||||
|
||||
A single-file Python status bar for Claude Code that shows everything you need at a glance — no API key required, zero dependencies, works with your existing Claude Code subscription.
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/demo.gif" alt="claude-pulse themes demo" width="700" />
|
||||
<br>
|
||||
<sub>10 built-in themes with colour-coded bars that shift green → yellow → red as usage increases</sub>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/rainbow.gif" alt="Rainbow animation demo" width="700" />
|
||||
<br>
|
||||
<sub>Rainbow animation — flowing gradient that shifts on every refresh</sub>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/update.gif" alt="Update notification demo" width="700" />
|
||||
<br>
|
||||
<sub>Automatic update notifications for both claude-pulse and Claude Code</sub>
|
||||
</p>
|
||||
|
||||
```
|
||||
Session ━━━───────── 27% 2h 53m | Weekly ━━━━━━━━━─── 73% R:Fri 3pm | Context ━━━━──────── 35% | $38.75 | +142 -37 | In Peak ⚡2x 2h 54m left (1pm-7pm) | Opus 4.6 | [\] 320 tools 51m | main
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Description |
|
||||
|---|---|
|
||||
| **Session & Weekly bars** | Colour-coded progress bars (green → yellow → red) for 5-hour session and 7-day weekly limits |
|
||||
| **Context window** | Live context usage percentage with pressure warnings at 70%/90% |
|
||||
| **Cost tracking** | Real-time session cost in your local currency (USD, GBP, EUR, + 25 more) with live exchange rates |
|
||||
| **Peak hours** | Configurable indicator for Anthropic's peak consumption window — red **In Peak ⚡** when limits burn faster, yellow when **approaching**, green **Off-Peak ✓** when limits stretch further. Full and minimal display modes |
|
||||
| **Live heartbeat** | Spinning indicator with tool count and elapsed time (via PostToolUse hook) |
|
||||
| **Git branch** | Current branch name always visible |
|
||||
| **Model display** | Shows which model is active (Opus, Sonnet, Haiku) |
|
||||
| **10 themes** | default, ocean, sunset, mono, neon, pride, frost, ember, candy, rainbow |
|
||||
| **5 animation modes** | off, rainbow, pulse, glow, shift — each visually distinct |
|
||||
| **8 bar styles** | classic, block, shade, pipe, dot, square, star, braille |
|
||||
| **Lines changed** | Shows `+42 -7` in green/red — lines added and removed this session, read from stdin |
|
||||
| **Cumulative cost** | Opt-in widget showing total API-equivalent cost across all sessions (cached, 5-min refresh) |
|
||||
| **Widget priorities** | Every widget has a priority number — reorder them with `--priority model=5,cost=15` |
|
||||
| **Focus timer** | Built-in focus timer — `--focus start 25` shows countdown in the status bar |
|
||||
| **Auto-updates** | Notifies when a new version of claude-pulse or Claude Code is available |
|
||||
| **Staleness indicator** | Shows data age when cached data is old |
|
||||
| **Zero API calls** | Reads rate limits directly from Claude Code's stdin (v2.1.80+) — no OAuth, no rate limiting |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Plugin marketplace (recommended)
|
||||
|
||||
```
|
||||
/plugin marketplace add NoobyGains/claude-pulse
|
||||
/plugin install claude-pulse
|
||||
```
|
||||
|
||||
Then run `/pulse` to configure. Restart Claude Code.
|
||||
|
||||
### One-liner install
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/NoobyGains/claude-pulse/main/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
irm https://raw.githubusercontent.com/NoobyGains/claude-pulse/main/install.ps1 | iex
|
||||
```
|
||||
|
||||
### Manual install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/NoobyGains/claude-pulse.git ~/.claude-pulse
|
||||
python3 ~/.claude-pulse/claude_status.py --install
|
||||
```
|
||||
|
||||
Restart Claude Code. That's it.
|
||||
|
||||
### Enable the live heartbeat (optional)
|
||||
|
||||
The heartbeat shows a tool counter and elapsed time, updated on every tool call:
|
||||
|
||||
```bash
|
||||
python3 ~/.claude-pulse/claude_status.py --install-hooks
|
||||
```
|
||||
|
||||
Restart Claude Code for hooks to take effect.
|
||||
|
||||
## Configuration
|
||||
|
||||
Use `/pulse` in Claude Code for an interactive setup wizard, or configure directly:
|
||||
|
||||
```bash
|
||||
# Themes
|
||||
--theme ocean # ocean, sunset, mono, neon, pride, frost, ember, candy, rainbow
|
||||
|
||||
# Animation
|
||||
--animate rainbow # rainbow, pulse, glow, shift, off
|
||||
--animation-speed fast # slow, normal, fast
|
||||
|
||||
# Display
|
||||
--bar-size large # small, small-medium, medium, medium-large, large
|
||||
--bar-style block # classic, block, shade, pipe, dot, square, star, braille
|
||||
--layout compact # standard, compact, minimal, percent-first
|
||||
--wrap auto # off (default, truncate) or auto (wrap to 2 lines at | when narrow)
|
||||
|
||||
# Currency (auto-converts USD via live exchange rate)
|
||||
--currency £ # $, £, €, ¥, C$, A$, ₹, kr, and 20+ more
|
||||
|
||||
# Peak hours (local time) — red in peak, green off-peak
|
||||
--peak-hours 13:00-19:00 # Set your peak window
|
||||
--peak-hours off # Disable peak indicator
|
||||
# Set "display": "minimal" in config for short format (⚡ Peak 2h)
|
||||
|
||||
# Clock
|
||||
--clock-format 12h # 12h or 24h
|
||||
|
||||
# Widget priority (lower = leftmost)
|
||||
--priority # Show all widget priorities
|
||||
--priority model=5,cost=15 # Move model first, cost after session
|
||||
|
||||
# Toggle features
|
||||
--show lines # Show +N/-N lines changed
|
||||
--show burn_rate # Show usage velocity (↑3%/hr)
|
||||
--show git_drift # Show commits ahead/behind
|
||||
--show cumulative_cost # Show total API-equivalent cost across all sessions
|
||||
--show files_changed # Show modified file count
|
||||
--show last_tool # Show last tool Claude used
|
||||
--hide cost # Hide cost ticker
|
||||
--hide heartbeat # Hide tool counter
|
||||
|
||||
# Focus timer
|
||||
--focus start 25 # Start a 25-minute focus timer
|
||||
--focus stop # Stop the timer
|
||||
--focus status # Check remaining time
|
||||
|
||||
# Info
|
||||
--config # Show current configuration
|
||||
--stats # Show session statistics
|
||||
--heatmap # Show activity heatmap
|
||||
--update # Update to latest version
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────┐
|
||||
│ Claude Code │
|
||||
│ Pipes JSON via stdin on every status refresh │
|
||||
│ (model, context %, cost, rate_limits) │
|
||||
├───────────────────────────────────────────────┤
|
||||
│ claude_status.py │
|
||||
│ Reads stdin → builds ANSI status line │
|
||||
│ No API calls needed (v2.1.80+) │
|
||||
├───────────────────────────────────────────────┤
|
||||
│ PostToolUse Hook (optional) │
|
||||
│ Updates tool count, heartbeat, git branch │
|
||||
│ on every tool call │
|
||||
├───────────────────────────────────────────────┤
|
||||
│ Cache Layer │
|
||||
│ Exchange rates (24h) · cumulative cost (5m) │
|
||||
│ hook state (5m) │
|
||||
│ Animation state · usage history │
|
||||
└───────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Data flow:** Claude Code sends session JSON via stdin → claude-pulse reads rate limits directly (no API) → renders colourised ANSI status line → Claude Code displays it.
|
||||
|
||||
**Rate limits from stdin (v2.1.80+):** Claude Code now includes `rate_limits.five_hour` and `rate_limits.seven_day` in the stdin JSON, so claude-pulse no longer needs to call the Anthropic OAuth API. This eliminates rate limiting issues entirely.
|
||||
|
||||
**PostToolUse hook:** When installed, the hook fires on every tool call (Read, Edit, Bash, etc.), updating the heartbeat counter and git branch. The status line refreshes on each tool call, making the spinner animate during active work.
|
||||
|
||||
## Themes
|
||||
|
||||
<p align="center">
|
||||
<img src="themes.png" alt="All 10 themes" width="700" />
|
||||
</p>
|
||||
|
||||
10 built-in themes with colour-coded bars that shift as usage increases. Set with `--theme <name>` or `/pulse <name>`.
|
||||
|
||||
## Animation Modes
|
||||
|
||||
| Mode | Effect |
|
||||
|---|---|
|
||||
| `off` | Static, no animation |
|
||||
| `rainbow` | Flowing rainbow gradient across the entire bar |
|
||||
| `pulse` | Bars cycle through vivid colours (cyan → blue → purple → pink → gold → green) |
|
||||
| `glow` | Per-character gradient that shifts across the bar each frame |
|
||||
| `shift` | Bright highlight slides across the bar |
|
||||
|
||||
Set with `--animate <mode>`. Animation moves on each status line refresh (interaction or tool call).
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Python 3.6+** (no pip installs needed)
|
||||
- **Claude Code** with a Pro or Max subscription
|
||||
- No API key required — uses Claude Code's existing credentials
|
||||
|
||||
## Security
|
||||
|
||||
- **No API calls for usage data** — reads rate limits directly from Claude Code's stdin (v2.1.80+)
|
||||
- OAuth tokens only used as fallback for extra credits/per-model caps, sent only to `api.anthropic.com` (hardcoded allowlist)
|
||||
- All file writes use atomic operations with 0o600 permissions
|
||||
- ANSI escape injection prevention on all external data
|
||||
- No `shell=True` in any subprocess call
|
||||
- Exchange rate API (frankfurter.app) — no auth, read-only, cached 24h
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Fix |
|
||||
|---|---|
|
||||
| No status line visible | Run `--install` then restart Claude Code |
|
||||
| "Rate limited" message | Update to v3.0.0+ — reads from stdin, no API calls needed |
|
||||
| Heartbeat not showing | Run `--install-hooks` then restart Claude Code. Shows after first tool call |
|
||||
| Heartbeat appears/disappears | Normal — shows when hook state is fresh (within 5 min of last tool call) |
|
||||
| Settings error after hook install | Run `/doctor` — hooks need nested format: `{matcher, hooks: [{type, command}]}` |
|
||||
| Stale data showing | Data refreshes on every interaction. If idle, it shows the last known state |
|
||||
| Unicode characters broken | Try `--bar-style block` for better Windows terminal support |
|
||||
|
||||
## Support
|
||||
|
||||
If this project helped you, consider starring the repo, sharing it with others, or buying me a coffee.
|
||||
|
||||
<a href="https://buymeacoffee.com/noobygains"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="200" /></a>
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#NoobyGains/claude-pulse&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=NoobyGains/claude-pulse&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=NoobyGains/claude-pulse&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=NoobyGains/claude-pulse&type=Date" width="700" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE) for details.
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
Made by <a href="https://github.com/NoobyGains">NoobyGains</a> · <a href="https://www.reddit.com/user/PigeonDroid/">PigeonDroid</a>
|
||||
</p>
|
||||
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/assets/claude-update.gif
vendored
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/assets/demo.gif
vendored
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
50
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/assets/logo.svg
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 250" width="700" height="250">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="#eb5f57"/>
|
||||
<stop offset="14%" stop-color="#f58b57"/>
|
||||
<stop offset="28%" stop-color="#fac35f"/>
|
||||
<stop offset="42%" stop-color="#91c882"/>
|
||||
<stop offset="57%" stop-color="#82aadc"/>
|
||||
<stop offset="71%" stop-color="#9b82c8"/>
|
||||
<stop offset="85%" stop-color="#c882b4"/>
|
||||
<stop offset="100%" stop-color="#eb5f57"/>
|
||||
</linearGradient>
|
||||
<filter id="g1"><feGaussianBlur stdDeviation="6"/></filter>
|
||||
<filter id="g2"><feGaussianBlur stdDeviation="12"/></filter>
|
||||
<filter id="g3"><feGaussianBlur stdDeviation="20"/></filter>
|
||||
</defs>
|
||||
|
||||
<rect width="700" height="250" fill="#0d1117" rx="16"/>
|
||||
|
||||
<!-- Wide ambient glow -->
|
||||
<polyline points="40,140 100,140 140,140 170,60 200,180 230,35 260,185 290,75 320,140 360,140 400,140"
|
||||
fill="none" stroke="url(#g)" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"
|
||||
opacity="0.15" filter="url(#g3)"/>
|
||||
|
||||
<!-- Medium glow -->
|
||||
<polyline points="40,140 100,140 140,140 170,60 200,180 230,35 260,185 290,75 320,140 360,140 400,140"
|
||||
fill="none" stroke="url(#g)" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"
|
||||
opacity="0.4" filter="url(#g2)"/>
|
||||
|
||||
<!-- Inner glow -->
|
||||
<polyline points="40,140 100,140 140,140 170,60 200,180 230,35 260,185 290,75 320,140 360,140 400,140"
|
||||
fill="none" stroke="url(#g)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"
|
||||
opacity="0.6" filter="url(#g1)"/>
|
||||
|
||||
<!-- Sharp line -->
|
||||
<polyline points="40,140 100,140 140,140 170,60 200,180 230,35 260,185 290,75 320,140 360,140 400,140"
|
||||
fill="none" stroke="url(#g)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
||||
<!-- "claude" in white -->
|
||||
<text x="430" y="120" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif"
|
||||
font-size="48" font-weight="700" fill="#ffffff" letter-spacing="-1">claude</text>
|
||||
|
||||
<!-- "pulse" in gradient -->
|
||||
<text x="430" y="168" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif"
|
||||
font-size="48" font-weight="300" fill="url(#g)" letter-spacing="-1">pulse</text>
|
||||
|
||||
<!-- Subtle tagline -->
|
||||
<text x="432" y="195" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif"
|
||||
font-size="13" fill="#8b949e" letter-spacing="0.5">real-time usage monitor for Claude Code</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/assets/rainbow.gif
vendored
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/assets/update.gif
vendored
Normal file
|
After Width: | Height: | Size: 174 KiB |
5082
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/claude_status.py
vendored
Normal file
235
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/commands/pulse.md
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
Configure your Claude status bars — themes, colours, animations, peak hours, and more. $ARGUMENTS
|
||||
|
||||
---
|
||||
|
||||
**Finding the script:** Before running any command below, you need the full path to `claude_status.py`. Do this ONCE at the start:
|
||||
|
||||
1. Read `~/.claude/settings.json`. If `statusLine.command` contains `claude_status.py`, extract the full script path from that string.
|
||||
2. If not found, use the Glob tool to search for `**/claude_status.py` inside `~/.claude/plugins/` — pick the result containing `claude-pulse`.
|
||||
3. If neither works, tell the user: "Run `/claude-pulse:setup` first to install the status bar."
|
||||
|
||||
Save the found path as SCRIPT_PATH. Use `python "SCRIPT_PATH"` for all commands below.
|
||||
|
||||
---
|
||||
|
||||
## ROUTING — decide what to do based on $ARGUMENTS
|
||||
|
||||
### Direct commands (skip the menu, run immediately):
|
||||
|
||||
If $ARGUMENTS matches a **theme name** (`default`, `ocean`, `sunset`, `mono`, `neon`, `pride`, `frost`, `ember`, `candy`, `rainbow`):
|
||||
-> Run `python "SCRIPT_PATH" --theme <name>` directly, no menu.
|
||||
-> Confirm: "Theme set to **<name>**. The status line will update on the next refresh."
|
||||
|
||||
If $ARGUMENTS is `config` or `settings`:
|
||||
-> Run `python "SCRIPT_PATH" --config` silently.
|
||||
-> Summarise the settings in your response text (don't show raw ANSI output).
|
||||
|
||||
If $ARGUMENTS is exactly `show` (no parts after it), or `show all`, or `colors`, or `colours`, or `preview`:
|
||||
-> Run TWO separate Bash commands (in parallel):
|
||||
1. `python "SCRIPT_PATH" --show-themes`
|
||||
2. `python "SCRIPT_PATH" --show-colors`
|
||||
-> Show the raw output to the user (coloured ANSI text with live previews).
|
||||
-> After both commands, say ONLY: "Press **Ctrl+O** to expand and see the colours."
|
||||
|
||||
If $ARGUMENTS contains `hide <parts>` or `show <parts>` (with specific parts):
|
||||
-> Run the corresponding `--hide` or `--show` command directly.
|
||||
-> Valid parts: session, weekly, context, timer, weekly_timer, cost, model, branch, heartbeat, activity, update, claude_update, opus, sonnet, effort, worktree, pomodoro, context_warning, staleness, plan, extra, burn_rate, sessions, last_tool, sparkline, runway, status_message, streak, pace, git_drift, files_changed
|
||||
|
||||
If $ARGUMENTS matches `animate <mode>` (where mode is `off`, `rainbow`, `pulse`, `glow`, `shift`, `on`):
|
||||
-> Run `--animate <mode>` directly.
|
||||
-> Explain what the mode does:
|
||||
- **off** — Static, no animation
|
||||
- **rainbow** — Flowing rainbow gradient across the entire bar
|
||||
- **pulse** — Bars cycle through vivid colours each refresh
|
||||
- **glow** — Per-character gradient that shifts across the bar
|
||||
- **shift** — Bright highlight slides across the bar
|
||||
|
||||
If $ARGUMENTS matches `text-color <name>` or `text-colour <name>`:
|
||||
-> Run `--text-color <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `currency <symbol>` (e.g. `currency £`, `currency €`, `currency $`):
|
||||
-> Run `--currency <symbol>` directly.
|
||||
-> Explain: cost is auto-converted from USD using a live exchange rate (cached 24h).
|
||||
|
||||
If $ARGUMENTS matches `bar-size <size>`:
|
||||
-> Run `--bar-size <size>` directly.
|
||||
|
||||
If $ARGUMENTS matches `bar-style <name>` or `style <name>`:
|
||||
-> Run `--bar-style <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `layout <name>`:
|
||||
-> Run `--layout <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `peak-hours <value>` or `peak <value>`:
|
||||
-> Run `--peak-hours <value>` directly.
|
||||
-> Examples: `peak-hours 13:00-19:00`, `peak-hours off`, `peak-hours on`
|
||||
|
||||
If $ARGUMENTS matches `animation-speed <speed>` or `speed <speed>`:
|
||||
-> Run `--animation-speed <speed>` directly.
|
||||
|
||||
If $ARGUMENTS matches `focus start [minutes]` or `focus stop` or `focus status`:
|
||||
-> Run `--focus <action> [minutes]` directly.
|
||||
-> Default is 25 minutes if no duration given.
|
||||
|
||||
If $ARGUMENTS matches `clock <format>` (where format is `12h` or `24h`):
|
||||
-> Run `--clock-format <format>` directly.
|
||||
|
||||
If $ARGUMENTS matches `preset <name>` or `minimal` or `default preset`:
|
||||
-> Run the corresponding `--preset` command.
|
||||
|
||||
If $ARGUMENTS is `update`:
|
||||
-> Run `python "SCRIPT_PATH" --update` and show the output.
|
||||
|
||||
If $ARGUMENTS is `hooks` or `install-hooks`:
|
||||
-> Run `python "SCRIPT_PATH" --install-hooks` and show the output.
|
||||
-> Remind user to restart Claude Code.
|
||||
|
||||
If $ARGUMENTS is `stats`:
|
||||
-> Run `python "SCRIPT_PATH" --stats` and show the output.
|
||||
|
||||
If $ARGUMENTS is `heatmap`:
|
||||
-> Run `python "SCRIPT_PATH" --heatmap` and show the output.
|
||||
|
||||
### Interactive menu (when $ARGUMENTS is empty, `themes`, `theme`, or `menu`):
|
||||
|
||||
**Step 0 — Quick tips:**
|
||||
|
||||
> **Quick commands:** `/pulse show` preview all themes · `/pulse ocean` set a theme · `/pulse config` see settings · `/pulse update` check for updates · `/pulse focus start` start a focus timer
|
||||
|
||||
Run `python "SCRIPT_PATH" --config` silently to check for updates.
|
||||
|
||||
**Step 1:** Run `python "SCRIPT_PATH" --themes-demo` and show the output.
|
||||
|
||||
**Step 2:** Theme picker (paginated as 3 pages):
|
||||
|
||||
Page 1:
|
||||
```
|
||||
Question: "Pick a theme from the preview above"
|
||||
Options:
|
||||
- "rainbow" — "Full-spectrum flowing colours"
|
||||
- "default" — "Classic green → yellow → red"
|
||||
- "ocean" — "Cool cyan → blue → magenta"
|
||||
- "More themes..." — "See all 10 themes"
|
||||
```
|
||||
|
||||
Page 2 (if "More themes..."):
|
||||
```
|
||||
Options:
|
||||
- "frost" — "Icy blue → steel → white"
|
||||
- "ember" — "Gold → hot orange → red"
|
||||
- "candy" — "Pink → purple → cyan"
|
||||
- "More themes..." — "See neon, sunset, pride, mono"
|
||||
```
|
||||
|
||||
Page 3 (if "More themes..." again):
|
||||
```
|
||||
Options:
|
||||
- "neon" — "Vivid bright green → yellow → red"
|
||||
- "sunset" — "Warm yellow → orange → red"
|
||||
- "pride" — "Violet → green → pink"
|
||||
- "mono" — "White → white → bright white"
|
||||
```
|
||||
|
||||
Apply with `--theme <name>`.
|
||||
|
||||
**Step 3:** Text colour (skip for rainbow):
|
||||
|
||||
Theme-specific recommendations: ocean→cyan, sunset/ember→yellow, frost→cyan, candy→pink, neon→green, pride→violet, default/mono→white.
|
||||
|
||||
```
|
||||
Question: "What colour for labels and percentages?"
|
||||
Options:
|
||||
- "<recommendation> (Recommended)" — "<reason>"
|
||||
- "White" — "Neutral, works with any theme"
|
||||
- "Auto" — "Best match for your theme"
|
||||
```
|
||||
|
||||
Apply with `--text-color <colour>`.
|
||||
|
||||
**Step 4:** Animation:
|
||||
|
||||
```
|
||||
Question: "Choose an animation style"
|
||||
Options:
|
||||
- "Off (Recommended)" — "Static theme colours, clean and simple"
|
||||
- "Rainbow" — "Flowing rainbow gradient"
|
||||
- "Pulse" — "Bars cycle through vivid colours"
|
||||
- "Glow" — "Gradient shifts across the bar"
|
||||
- "Shift" — "Bright highlight slides across"
|
||||
```
|
||||
|
||||
Apply with `--animate <mode>`.
|
||||
|
||||
**Step 5:** Bar size:
|
||||
|
||||
```
|
||||
Question: "How wide should the progress bars be?"
|
||||
Options:
|
||||
- "Large (Recommended)" — "12 characters — detailed bars"
|
||||
- "Medium" — "8 characters — balanced"
|
||||
- "Small" — "4 characters — compact"
|
||||
```
|
||||
|
||||
Apply with `--bar-size <size>`.
|
||||
|
||||
**Step 6:** Currency:
|
||||
|
||||
```
|
||||
Question: "What currency for the cost ticker?"
|
||||
Options:
|
||||
- "$ (USD)" — "US Dollar (base currency)"
|
||||
- "£ (GBP)" — "British Pound (auto-converted)"
|
||||
- "€ (EUR)" — "Euro (auto-converted)"
|
||||
- "Other" — "Type any symbol (¥, ₹, C$, kr, etc.)"
|
||||
```
|
||||
|
||||
Apply with `--currency <symbol>`. Explain: the cost shows what this session would cost at API rates, converted to their currency via live exchange rate.
|
||||
|
||||
**Step 7:** Peak hours:
|
||||
|
||||
```
|
||||
Question: "Enable peak hours indicator? (Anthropic's 2x consumption window)"
|
||||
Options:
|
||||
- "On — 1pm-7pm (Recommended)" — "Default window matching known peak times"
|
||||
- "Custom" — "Set your own peak window"
|
||||
- "Off" — "Don't show peak indicator"
|
||||
```
|
||||
|
||||
If "Custom", ask for start and end time (HH:MM format). Apply with `--peak-hours <start>-<end>`.
|
||||
If "On", apply `--peak-hours on`.
|
||||
If "Off", apply `--peak-hours off`.
|
||||
|
||||
**Step 8:** Clock format:
|
||||
|
||||
```
|
||||
Question: "Clock format for timers?"
|
||||
Options:
|
||||
- "12h" — "Fri 5pm"
|
||||
- "24h" — "Fri 17:00"
|
||||
```
|
||||
|
||||
Apply with `--clock-format <12h|24h>`.
|
||||
|
||||
**Step 9:** Live heartbeat hook:
|
||||
|
||||
```
|
||||
Question: "Install the live heartbeat hook? (shows tool counter during active work)"
|
||||
Options:
|
||||
- "Yes (Recommended)" — "Adds [/] 42 tools 5m to your status bar"
|
||||
- "No" — "Skip — you can install later with /pulse hooks"
|
||||
```
|
||||
|
||||
If "Yes", run `python "SCRIPT_PATH" --install-hooks`. Remind to restart Claude Code.
|
||||
|
||||
**Step 10:** Confirm everything:
|
||||
"All set! Your status bar is configured with **<theme>**, **<animation>** animation, **<currency>** cost tracking, and peak hours **<on/off>**. It updates on every interaction."
|
||||
|
||||
If hooks were installed: "Restart Claude Code to activate the live heartbeat."
|
||||
|
||||
---
|
||||
|
||||
## DISPLAY RULES
|
||||
|
||||
- After any change, tell the user it will update on the next refresh.
|
||||
- When running `--config`, summarise — don't show raw ANSI.
|
||||
- Be brief and enthusiastic.
|
||||
16
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/commands/setup.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
Set up the claude-pulse status bar. This is a one-time setup.
|
||||
|
||||
---
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Find the script.** Use the Glob tool to search for `claude_status.py` inside `~/.claude/plugins/` recursively. The pattern is `**/claude_status.py`. Use the result that contains `claude-pulse` in the path. Save this as SCRIPT_PATH.
|
||||
|
||||
2. **Run the installer.** Execute: `python "SCRIPT_PATH" --install`
|
||||
|
||||
This adds the status line command and animation hooks to `~/.claude/settings.json`.
|
||||
|
||||
3. **Confirm to the user:**
|
||||
- "claude-pulse is installed! Restart Claude Code to see your status bar."
|
||||
- "Type `/claude-pulse:pulse` to configure themes, colours, and animations."
|
||||
- "Type `/claude-pulse:pulse show` to preview all themes."
|
||||
54
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/config.json
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"cache_ttl_seconds": 60,
|
||||
"theme": "default",
|
||||
"text_color": "auto",
|
||||
"animate": "off",
|
||||
"animation_speed": "normal",
|
||||
"bar_size": "large",
|
||||
"bar_style": "classic",
|
||||
"layout": "standard",
|
||||
"max_width": 80,
|
||||
"context_format": "percent",
|
||||
"weekly_timer_format": "auto",
|
||||
"clock_format": "12h",
|
||||
"extra_display": "auto",
|
||||
"currency": "$",
|
||||
"peak_hours": {
|
||||
"enabled": true,
|
||||
"start": "13:00",
|
||||
"end": "19:00"
|
||||
},
|
||||
"show": {
|
||||
"session": true,
|
||||
"weekly": true,
|
||||
"context": true,
|
||||
"timer": true,
|
||||
"weekly_timer": true,
|
||||
"cost": true,
|
||||
"model": true,
|
||||
"branch": true,
|
||||
"heartbeat": true,
|
||||
"activity": true,
|
||||
"update": true,
|
||||
"claude_update": true,
|
||||
"opus": true,
|
||||
"sonnet": true,
|
||||
"effort": true,
|
||||
"worktree": true,
|
||||
"pomodoro": true,
|
||||
"context_warning": true,
|
||||
"staleness": true,
|
||||
"plan": false,
|
||||
"extra": false,
|
||||
"burn_rate": false,
|
||||
"sessions": false,
|
||||
"last_tool": false,
|
||||
"sparkline": false,
|
||||
"runway": false,
|
||||
"status_message": false,
|
||||
"streak": false,
|
||||
"pace": false,
|
||||
"git_drift": false,
|
||||
"files_changed": false
|
||||
}
|
||||
}
|
||||
687
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/generate_gif.py
vendored
Normal file
@@ -0,0 +1,687 @@
|
||||
"""Generate an animated GIF showcasing claude-pulse inside Claude Code."""
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
THEME_CSS = {
|
||||
"default": {"low": "#22c55e", "mid": "#eab308", "high": "#ef4444"},
|
||||
"ocean": {"low": "#06b6d4", "mid": "#3b82f6", "high": "#a855f7"},
|
||||
"sunset": {"low": "#eab308", "mid": "#ff8800", "high": "#ef4444"},
|
||||
"neon": {"low": "#4ade80", "mid": "#facc15", "high": "#f87171"},
|
||||
"frost": {"low": "#afffff", "mid": "#5fafff", "high": "#ffffff"},
|
||||
"ember": {"low": "#ffd700", "mid": "#ff5f00", "high": "#f87171"},
|
||||
"candy": {"low": "#ff87ff", "mid": "#af87ff", "high": "#00ffff"},
|
||||
"pride": {"low": "#af5fff", "mid": "#00ffaf", "high": "#ff00af"},
|
||||
"mono": {"low": "#d1d5db", "mid": "#d1d5db", "high": "#ffffff"},
|
||||
"rainbow": {"low": "#ff0000", "mid": "#00ff00", "high": "#ff00ff"},
|
||||
}
|
||||
|
||||
DIM_COLOR = "#3a3a3a"
|
||||
RAINBOW_COLORS = ["#ff0000", "#ff8800", "#ffff00", "#00ff00", "#00ccff",
|
||||
"#0066ff", "#8800ff", "#ff00ff", "#ff0066", "#ff4444"]
|
||||
|
||||
# Claude "Claw'd" pixel mascot as CSS pixel art (16x12 grid)
|
||||
# R = coral body, D = dark eyes, . = transparent
|
||||
# Square design: 12px wide body, 2px arm nubs on each side
|
||||
MASCOT_PIXELS = [
|
||||
"..RRRRRRRRRRRR..",
|
||||
"..RRRRRRRRRRRR..",
|
||||
"..RDDRRRRRRDDR..",
|
||||
"..RDDRRRRRRDDR..",
|
||||
"..RRRRRRRRRRRR..",
|
||||
"RRRRRRRRRRRRRRRR",
|
||||
"RRRRRRRRRRRRRRRR",
|
||||
"..RRRRRRRRRRRR..",
|
||||
"..RRRRRRRRRRRR..",
|
||||
"..RRRRRRRRRRRR..",
|
||||
"..RR.RR..RR.RR..",
|
||||
"..RR.RR..RR.RR..",
|
||||
]
|
||||
|
||||
|
||||
def mascot_html():
|
||||
"""Render the Claude pixel mascot as CSS grid pixel art."""
|
||||
rows = []
|
||||
for row in MASCOT_PIXELS:
|
||||
for ch in row:
|
||||
if ch == "R":
|
||||
rows.append('<span class="px pr"></span>')
|
||||
elif ch == "D":
|
||||
rows.append('<span class="px pd"></span>')
|
||||
elif ch == "N":
|
||||
rows.append('<span class="px pn"></span>')
|
||||
else:
|
||||
rows.append('<span class="px"></span>')
|
||||
return "\n ".join(rows)
|
||||
|
||||
|
||||
def bar_color(pct, theme):
|
||||
if pct >= 80:
|
||||
return theme["high"]
|
||||
if pct >= 50:
|
||||
return theme["mid"]
|
||||
return theme["low"]
|
||||
|
||||
|
||||
def render_bar_html(pct, theme, width=10, rainbow=False, color_offset=0):
|
||||
filled = round(pct / 100 * width)
|
||||
filled = max(0, min(width, filled))
|
||||
empty = width - filled
|
||||
e_chars = "\u2500" * empty
|
||||
if rainbow and filled > 0:
|
||||
parts = ""
|
||||
for j in range(filled):
|
||||
c = RAINBOW_COLORS[(j + color_offset) % len(RAINBOW_COLORS)]
|
||||
parts += f'<span style="color:{c}">\u2501</span>'
|
||||
return f'{parts}<span style="color:{DIM_COLOR}">{e_chars}</span>'
|
||||
color = bar_color(pct, theme)
|
||||
f_chars = "\u2501" * filled
|
||||
return f'<span style="color:{color}">{f_chars}</span><span style="color:{DIM_COLOR}">{e_chars}</span>'
|
||||
|
||||
|
||||
def generate_frame_html(theme_name, theme, session_pct, weekly_pct, ctx_pct,
|
||||
reset_time, plan, model, frame_num, total_frames, desc,
|
||||
is_rainbow=False, color_offset=0,
|
||||
extra_used="", extra_limit="",
|
||||
show_update=False):
|
||||
session_bar = render_bar_html(session_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset)
|
||||
weekly_bar = render_bar_html(weekly_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset + 3)
|
||||
ctx_bar = render_bar_html(ctx_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset + 6)
|
||||
|
||||
text_color = "#d1d5db"
|
||||
sep = f'<span class="sep">|</span>'
|
||||
sp = f"{session_pct:3d}%"
|
||||
wp = f"{weekly_pct:3d}%"
|
||||
cp = f"{ctx_pct:3d}%"
|
||||
reset_str = f" {reset_time}" if reset_time else " "
|
||||
|
||||
extra_part = ""
|
||||
if extra_used and extra_limit:
|
||||
extra_pct = 100 * float(extra_used.replace("£", "")) / float(extra_limit.replace("£", ""))
|
||||
extra_bar = render_bar_html(extra_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset + 9)
|
||||
extra_part = (
|
||||
f'{sep}'
|
||||
f'<span class="sl">Extra </span>{extra_bar}'
|
||||
f'<span class="sl"> {extra_used}/{extra_limit}</span>'
|
||||
)
|
||||
|
||||
update_part = ""
|
||||
if show_update:
|
||||
update_part = f'{sep}<span style="color:#eab308;font-weight:bold">↑ Pulse Update</span>'
|
||||
|
||||
status = (
|
||||
f'<span class="sl">Session </span>{session_bar}'
|
||||
f'<span class="sl"> {sp}{reset_str}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">Weekly </span>{weekly_bar}'
|
||||
f'<span class="sl"> {wp}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">Context </span>{ctx_bar}'
|
||||
f'<span class="sl"> {cp}</span>'
|
||||
f'{extra_part}'
|
||||
f'{update_part}'
|
||||
f'{sep}'
|
||||
f'<span class="sl">{plan}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">{model}</span>'
|
||||
)
|
||||
|
||||
badge_color = theme["low"]
|
||||
mascot = mascot_html()
|
||||
|
||||
return f'''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');
|
||||
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
||||
body {{
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
font-family: 'JetBrains Mono', 'Cascadia Code', 'Consolas', monospace;
|
||||
}}
|
||||
.terminal {{
|
||||
background: #0c0c0c;
|
||||
border-radius: 8px;
|
||||
width: 920px;
|
||||
height: 430px;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.08);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}}
|
||||
.titlebar {{
|
||||
background: #202020;
|
||||
padding: 7px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #2a2a2a;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
.tab {{
|
||||
background: #0c0c0c;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
padding: 5px 14px;
|
||||
border-radius: 6px 6px 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border: 1px solid #2a2a2a;
|
||||
border-bottom: none;
|
||||
margin-bottom: -1px;
|
||||
}}
|
||||
.tab-icon {{ color: #0078d4; font-size: 13px; }}
|
||||
.spacer {{ flex: 1; }}
|
||||
.win-controls {{ display: flex; gap: 0; }}
|
||||
.win-btn {{
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
padding: 4px 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}}
|
||||
|
||||
.body {{ flex: 1; display: flex; flex-direction: column; overflow: hidden; }}
|
||||
|
||||
.conversation {{
|
||||
flex: 1;
|
||||
padding: 14px 20px;
|
||||
overflow: hidden;
|
||||
}}
|
||||
|
||||
/* ── Header ── */
|
||||
.cc-title {{
|
||||
color: #d4a574;
|
||||
font-size: 12px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #d4a57433;
|
||||
}}
|
||||
|
||||
/* ── Two-column welcome ── */
|
||||
.welcome-row {{
|
||||
display: flex;
|
||||
gap: 0;
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid #d4a57455;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}}
|
||||
.welcome-left {{
|
||||
flex: 0 0 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 12px 10px;
|
||||
border-right: 1px solid #d4a57433;
|
||||
}}
|
||||
.welcome-greeting {{
|
||||
color: #e0e0e0;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}}
|
||||
.welcome-right {{
|
||||
flex: 1;
|
||||
padding: 12px 14px;
|
||||
}}
|
||||
|
||||
/* Pixel mascot */
|
||||
.mascot {{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(16, 6px);
|
||||
grid-template-rows: repeat(12, 6px);
|
||||
gap: 1px;
|
||||
margin-bottom: 8px;
|
||||
}}
|
||||
.px {{ width: 6px; height: 6px; background: transparent; }}
|
||||
.pr {{ background: #d4735c; }}
|
||||
.pd {{ background: #1a1a1a; }}
|
||||
.pn {{ background: #b85e48; }}
|
||||
|
||||
.welcome-meta {{
|
||||
color: #888;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
}}
|
||||
|
||||
/* Right column */
|
||||
.section-title {{
|
||||
color: #d4a574;
|
||||
font-size: 11px;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}}
|
||||
.tip-text {{
|
||||
color: #888;
|
||||
font-size: 10.5px;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10px;
|
||||
}}
|
||||
.recent-text {{
|
||||
color: #666;
|
||||
font-size: 10.5px;
|
||||
}}
|
||||
|
||||
/* ── User message + Claude reply ── */
|
||||
.user-msg {{
|
||||
margin-bottom: 8px;
|
||||
margin-top: 4px;
|
||||
}}
|
||||
.user-prompt {{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}}
|
||||
.user-prompt .arrow {{ color: #b388ff; font-size: 12px; }}
|
||||
.user-text {{
|
||||
color: #e0e0e0;
|
||||
font-size: 12.5px;
|
||||
font-weight: 500;
|
||||
}}
|
||||
|
||||
.claude-reply {{
|
||||
margin-bottom: 8px;
|
||||
}}
|
||||
.claude-reply .dot {{ color: #b388ff; font-size: 12px; }}
|
||||
.claude-reply-text {{
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}}
|
||||
|
||||
/* Prompt cursor */
|
||||
.prompt-line {{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
}}
|
||||
.prompt-arrow {{ color: #b388ff; }}
|
||||
.cursor {{
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 15px;
|
||||
background: #b388ff;
|
||||
opacity: 0.7;
|
||||
}}
|
||||
|
||||
/* ── Divider ── */
|
||||
.divider {{
|
||||
border-top: 1px solid #222;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
|
||||
/* ── Status bar ── */
|
||||
.status-area {{
|
||||
padding: 8px 20px 6px 20px;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
.status-line {{
|
||||
font-size: 11.5px;
|
||||
line-height: 1.5;
|
||||
white-space: pre;
|
||||
letter-spacing: 0;
|
||||
font-variant-ligatures: none;
|
||||
}}
|
||||
.sl {{ color: {text_color}; }}
|
||||
.sep {{ color: #555; padding: 0 0.3em; }}
|
||||
|
||||
/* ── Mode indicator ── */
|
||||
.mode-bar {{
|
||||
padding: 2px 20px 10px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
.mode-icon {{ color: #b388ff; font-size: 11px; }}
|
||||
.mode-text {{ color: #666; font-size: 11px; }}
|
||||
.mode-hint {{ color: #444; font-size: 10px; }}
|
||||
|
||||
/* ── Theme badge ── */
|
||||
.theme-overlay {{
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}}
|
||||
.theme-badge {{
|
||||
display: inline-block;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border: 1px solid {badge_color}44;
|
||||
color: {badge_color};
|
||||
padding: 3px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
}}
|
||||
.frame-counter {{
|
||||
color: #444;
|
||||
font-size: 10px;
|
||||
letter-spacing: 1px;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="terminal">
|
||||
<div class="titlebar">
|
||||
<div class="tab"><span class="tab-icon">❯</span> Windows PowerShell</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="win-controls">
|
||||
<span class="win-btn">─</span>
|
||||
<span class="win-btn">□</span>
|
||||
<span class="win-btn close">✕</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
<div class="conversation">
|
||||
<div class="cc-title">Claude Code v2.1.36</div>
|
||||
|
||||
<div class="welcome-row">
|
||||
<div class="welcome-left">
|
||||
<div class="welcome-greeting">Welcome back NoobyGains!</div>
|
||||
<div class="mascot">
|
||||
{mascot}
|
||||
</div>
|
||||
<div class="welcome-meta">
|
||||
{model} · Claude Max<br>
|
||||
C:\\Users\\David
|
||||
</div>
|
||||
</div>
|
||||
<div class="welcome-right">
|
||||
<div class="section-title">Tips for getting started</div>
|
||||
<div class="tip-text">
|
||||
Run <span style="color:#b388ff">/init</span> to create a CLAUDE.md file with instructions for Claude<br>
|
||||
Note: You have launched claude in your home directory. For the best<br>
|
||||
experience, navigate to a project folder first.
|
||||
</div>
|
||||
<div class="section-title">Recent activity</div>
|
||||
<div class="recent-text">No recent activity</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-msg">
|
||||
<div class="user-prompt">
|
||||
<span class="arrow">❯</span>
|
||||
<span class="user-text">hello</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="claude-reply">
|
||||
<div class="claude-reply-text">
|
||||
<span class="dot">●</span>
|
||||
Hello! How can I help you today?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prompt-line">
|
||||
<span class="prompt-arrow">❯</span>
|
||||
<span class="cursor"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="status-area">
|
||||
<div class="status-line">{status}</div>
|
||||
</div>
|
||||
<div class="mode-bar">
|
||||
<span class="mode-icon">⏵⏵</span>
|
||||
<span class="mode-text">auto-accept edits</span>
|
||||
<span class="mode-hint">(shift+tab to cycle)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-overlay">
|
||||
<span class="theme-badge">{theme_name}</span>
|
||||
<span class="frame-counter">{frame_num}/{total_frames}</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>'''
|
||||
|
||||
|
||||
def generate_statusline_html(theme_name, theme, session_pct, weekly_pct, ctx_pct,
|
||||
reset_time, plan, model, frame_num, total_frames,
|
||||
is_rainbow=False, color_offset=0,
|
||||
show_update=False, show_claude_update=False):
|
||||
"""Render just the status line bar — no terminal chrome."""
|
||||
session_bar = render_bar_html(session_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset)
|
||||
weekly_bar = render_bar_html(weekly_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset + 3)
|
||||
ctx_bar = render_bar_html(ctx_pct, theme, 10, rainbow=is_rainbow, color_offset=color_offset + 6)
|
||||
|
||||
text_color = "#d1d5db"
|
||||
sep = '<span class="sep">|</span>'
|
||||
sp = f"{session_pct:3d}%"
|
||||
wp = f"{weekly_pct:3d}%"
|
||||
cp = f"{ctx_pct:3d}%"
|
||||
reset_str = f" {reset_time}" if reset_time else " "
|
||||
|
||||
update_part = ""
|
||||
if show_update:
|
||||
update_part = f'{sep}<span style="color:#eab308;font-weight:bold">↑ Pulse Update</span>'
|
||||
if show_claude_update:
|
||||
update_part += f'{sep}<span style="color:#eab308;font-weight:bold">↑ Claude Update</span>'
|
||||
|
||||
status = (
|
||||
f'<span class="sl">Session </span>{session_bar}'
|
||||
f'<span class="sl"> {sp}{reset_str}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">Weekly </span>{weekly_bar}'
|
||||
f'<span class="sl"> {wp}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">Context </span>{ctx_bar}'
|
||||
f'<span class="sl"> {cp}</span>'
|
||||
f'{update_part}'
|
||||
f'{sep}'
|
||||
f'<span class="sl">{plan}</span>'
|
||||
f'{sep}'
|
||||
f'<span class="sl">{model}</span>'
|
||||
)
|
||||
|
||||
return f'''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');
|
||||
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
||||
body {{
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60px;
|
||||
font-family: 'JetBrains Mono', 'Cascadia Code', 'Consolas', monospace;
|
||||
}}
|
||||
.bar {{
|
||||
background: #0c0c0c;
|
||||
padding: 10px 20px;
|
||||
width: 920px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #333;
|
||||
}}
|
||||
.status-line {{
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
white-space: pre;
|
||||
letter-spacing: 0;
|
||||
font-variant-ligatures: none;
|
||||
}}
|
||||
.sl {{ color: {text_color}; }}
|
||||
.sep {{ color: #555; padding: 0 0.3em; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bar">
|
||||
<div class="status-line">{status}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>'''
|
||||
|
||||
|
||||
def main():
|
||||
themes_to_show = ["default", "ocean", "sunset", "neon", "frost", "ember", "candy", "pride", "mono"]
|
||||
frames_data = []
|
||||
|
||||
# (session%, weekly%, ctx%, reset_time, desc, extra_used, extra_limit)
|
||||
scenarios = [
|
||||
(12, 6, 8, "4h 52m", "low usage", "£3.10", "£37.00"),
|
||||
(38, 22, 30, "3h 14m", "warming up", "£8.20", "£37.00"),
|
||||
(62, 45, 55, "1h 48m", "active session", "£22.50", "£37.00"),
|
||||
(88, 68, 82, "0h 22m", "near limit", "£34.80", "£37.00"),
|
||||
]
|
||||
|
||||
for theme_name in themes_to_show:
|
||||
theme = THEME_CSS[theme_name]
|
||||
for session_pct, weekly_pct, ctx_pct, reset, desc, eu, el in scenarios:
|
||||
frames_data.append((
|
||||
theme_name, theme, session_pct, weekly_pct, ctx_pct,
|
||||
reset, "Max 20x", "Opus 4.6", desc, False, 0, eu, el
|
||||
))
|
||||
|
||||
rainbow_theme = THEME_CSS["rainbow"]
|
||||
for offset in range(10):
|
||||
frames_data.append((
|
||||
"rainbow", rainbow_theme, 55, 38, 45,
|
||||
"2h 10m", "Max 20x", "Opus 4.6", "animated shimmer", True, offset,
|
||||
"£18.50", "£37.00"
|
||||
))
|
||||
|
||||
tmp_dir = Path(tempfile.mkdtemp())
|
||||
html_paths = []
|
||||
total = len(frames_data)
|
||||
|
||||
for i, (tname, theme, sp, wp, cp, reset, plan, model, desc, is_rb, c_off, eu, el) in enumerate(frames_data):
|
||||
html = generate_frame_html(
|
||||
tname, theme, sp, wp, cp, reset, plan, model,
|
||||
i + 1, total, desc, is_rainbow=is_rb, color_offset=c_off,
|
||||
extra_used=eu, extra_limit=el
|
||||
)
|
||||
html_path = tmp_dir / f"frame_{i:03d}.html"
|
||||
html_path.write_text(html, encoding="utf-8")
|
||||
html_paths.append(str(html_path))
|
||||
|
||||
manifest = tmp_dir / "manifest.json"
|
||||
manifest.write_text(json.dumps(html_paths), encoding="utf-8")
|
||||
|
||||
output_gif = Path(__file__).parent / "assets" / "demo.gif"
|
||||
output_gif.parent.mkdir(exist_ok=True)
|
||||
|
||||
print(f"Generated {len(html_paths)} HTML frames in {tmp_dir}")
|
||||
print(json.dumps({
|
||||
"tmp_dir": str(tmp_dir),
|
||||
"output_gif": str(output_gif),
|
||||
"frame_count": len(html_paths),
|
||||
}))
|
||||
|
||||
# ── Second GIF: update notification (status line only, no Extra) ──
|
||||
update_frames = []
|
||||
update_scenarios = [
|
||||
(42, 28, 35, "2h 40m", "with update"),
|
||||
(65, 50, 60, "1h 15m", "with update"),
|
||||
(85, 72, 78, "0h 30m", "with update"),
|
||||
]
|
||||
for tname in themes_to_show:
|
||||
theme = THEME_CSS[tname]
|
||||
for sp, wp, cp, reset, desc in update_scenarios:
|
||||
update_frames.append((tname, theme, sp, wp, cp, reset,
|
||||
"Max 20x", "Opus 4.6", desc, False, 0))
|
||||
|
||||
# Rainbow shimmer for update GIF too
|
||||
for offset in range(10):
|
||||
update_frames.append((
|
||||
"rainbow", THEME_CSS["rainbow"], 55, 38, 45,
|
||||
"2h 10m", "Max 20x", "Opus 4.6", "shimmer", True, offset
|
||||
))
|
||||
|
||||
tmp_dir2 = Path(tempfile.mkdtemp())
|
||||
html_paths2 = []
|
||||
total2 = len(update_frames)
|
||||
|
||||
for i, (tname, theme, sp, wp, cp, reset, plan, model, desc, is_rb, c_off) in enumerate(update_frames):
|
||||
html = generate_statusline_html(
|
||||
tname, theme, sp, wp, cp, reset, plan, model,
|
||||
i + 1, total2, is_rainbow=is_rb, color_offset=c_off,
|
||||
show_update=True
|
||||
)
|
||||
html_path = tmp_dir2 / f"update_{i:03d}.html"
|
||||
html_path.write_text(html, encoding="utf-8")
|
||||
html_paths2.append(str(html_path))
|
||||
|
||||
manifest2 = tmp_dir2 / "manifest.json"
|
||||
manifest2.write_text(json.dumps(html_paths2), encoding="utf-8")
|
||||
|
||||
output_gif2 = Path(__file__).parent / "assets" / "update.gif"
|
||||
print(f"Generated {len(html_paths2)} update frames in {tmp_dir2}")
|
||||
print(json.dumps({
|
||||
"tmp_dir2": str(tmp_dir2),
|
||||
"output_gif2": str(output_gif2),
|
||||
"frame_count2": len(html_paths2),
|
||||
}))
|
||||
|
||||
# ── Third GIF: Claude Code update notification (status line only) ──
|
||||
cc_update_frames = []
|
||||
cc_update_scenarios = [
|
||||
(42, 28, 35, "2h 40m", "with claude update"),
|
||||
(65, 50, 60, "1h 15m", "with claude update"),
|
||||
(85, 72, 78, "0h 30m", "with claude update"),
|
||||
]
|
||||
for tname in themes_to_show:
|
||||
theme = THEME_CSS[tname]
|
||||
for sp, wp, cp, reset, desc in cc_update_scenarios:
|
||||
cc_update_frames.append((tname, theme, sp, wp, cp, reset,
|
||||
"Max 20x", "Opus 4.6", desc, False, 0))
|
||||
|
||||
# Rainbow shimmer for claude update GIF too
|
||||
for offset in range(10):
|
||||
cc_update_frames.append((
|
||||
"rainbow", THEME_CSS["rainbow"], 55, 38, 45,
|
||||
"2h 10m", "Max 20x", "Opus 4.6", "shimmer", True, offset
|
||||
))
|
||||
|
||||
tmp_dir3 = Path(tempfile.mkdtemp())
|
||||
html_paths3 = []
|
||||
total3 = len(cc_update_frames)
|
||||
|
||||
for i, (tname, theme, sp, wp, cp, reset, plan, model, desc, is_rb, c_off) in enumerate(cc_update_frames):
|
||||
html = generate_statusline_html(
|
||||
tname, theme, sp, wp, cp, reset, plan, model,
|
||||
i + 1, total3, is_rainbow=is_rb, color_offset=c_off,
|
||||
show_claude_update=True
|
||||
)
|
||||
html_path = tmp_dir3 / f"claude_update_{i:03d}.html"
|
||||
html_path.write_text(html, encoding="utf-8")
|
||||
html_paths3.append(str(html_path))
|
||||
|
||||
manifest3 = tmp_dir3 / "manifest.json"
|
||||
manifest3.write_text(json.dumps(html_paths3), encoding="utf-8")
|
||||
|
||||
output_gif3 = Path(__file__).parent / "assets" / "claude-update.gif"
|
||||
print(f"Generated {len(html_paths3)} claude update frames in {tmp_dir3}")
|
||||
print(json.dumps({
|
||||
"tmp_dir3": str(tmp_dir3),
|
||||
"output_gif3": str(output_gif3),
|
||||
"frame_count3": len(html_paths3),
|
||||
}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
93
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/install.ps1
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$RepoSlug = "NoobyGains/claude-pulse"
|
||||
$RepoUrl = "https://github.com/$RepoSlug.git"
|
||||
$RawBaseUrl = "https://raw.githubusercontent.com/$RepoSlug/main"
|
||||
|
||||
$InstallDir = if ($env:CLAUDE_PULSE_DIR) { $env:CLAUDE_PULSE_DIR } else { Join-Path $HOME ".claude-pulse" }
|
||||
$ClaudeDir = if ($env:CLAUDE_CONFIG_DIR) { $env:CLAUDE_CONFIG_DIR } else { Join-Path $HOME ".claude" }
|
||||
$CommandsDir = Join-Path $ClaudeDir "commands"
|
||||
|
||||
$InstallMethod = ""
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host $Message
|
||||
}
|
||||
|
||||
function Throw-IfFailed {
|
||||
param([string]$Message)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw $Message
|
||||
}
|
||||
}
|
||||
|
||||
function Download-Files {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
Invoke-WebRequest -Uri "$RawBaseUrl/claude_status.py" -OutFile (Join-Path $InstallDir "claude_status.py")
|
||||
Invoke-WebRequest -Uri "$RawBaseUrl/pulse.md" -OutFile (Join-Path $InstallDir "pulse.md")
|
||||
$script:InstallMethod = "raw"
|
||||
}
|
||||
|
||||
if (Get-Command git -ErrorAction SilentlyContinue) {
|
||||
if (Test-Path (Join-Path $InstallDir ".git")) {
|
||||
$originUrl = (git -C $InstallDir remote get-url origin).Trim()
|
||||
Throw-IfFailed "Failed to read git origin from $InstallDir"
|
||||
if ($originUrl -notmatch "NoobyGains/claude-pulse(\.git)?$") {
|
||||
throw "Existing git repo at '$InstallDir' has unexpected origin '$originUrl'"
|
||||
}
|
||||
|
||||
Write-Step "Updating existing claude-pulse clone..."
|
||||
git -C $InstallDir pull --ff-only origin main | Out-Null
|
||||
Throw-IfFailed "Failed to update git clone"
|
||||
$InstallMethod = "git"
|
||||
}
|
||||
elseif (Test-Path (Join-Path $InstallDir "claude_status.py")) {
|
||||
Write-Step "Existing non-git install detected, refreshing files..."
|
||||
Download-Files
|
||||
}
|
||||
elseif (Test-Path $InstallDir) {
|
||||
throw "Directory already exists and is not a claude-pulse install: $InstallDir"
|
||||
}
|
||||
else {
|
||||
$parentDir = Split-Path -Parent $InstallDir
|
||||
if ($parentDir -and -not (Test-Path $parentDir)) {
|
||||
New-Item -ItemType Directory -Path $parentDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Step "Cloning claude-pulse..."
|
||||
git clone --depth 1 $RepoUrl $InstallDir | Out-Null
|
||||
Throw-IfFailed "Failed to clone repository"
|
||||
$InstallMethod = "git"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Step "git not found, downloading scripts directly..."
|
||||
Download-Files
|
||||
}
|
||||
|
||||
$PulseCommandPath = Join-Path $InstallDir "pulse.md"
|
||||
if (Test-Path $PulseCommandPath) {
|
||||
New-Item -ItemType Directory -Path $CommandsDir -Force | Out-Null
|
||||
Copy-Item -Path $PulseCommandPath -Destination (Join-Path $CommandsDir "pulse.md") -Force
|
||||
}
|
||||
|
||||
$StatusScriptPath = Join-Path $InstallDir "claude_status.py"
|
||||
if (Get-Command python -ErrorAction SilentlyContinue) {
|
||||
& python $StatusScriptPath --install
|
||||
Throw-IfFailed "Python installer command failed"
|
||||
}
|
||||
elseif (Get-Command py -ErrorAction SilentlyContinue) {
|
||||
& py -3 $StatusScriptPath --install
|
||||
Throw-IfFailed "Python launcher installer command failed"
|
||||
}
|
||||
else {
|
||||
throw "Python 3 is required. Install Python, then run this installer again."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "claude-pulse installed in: $InstallDir"
|
||||
Write-Host "Restart Claude Code, then run /pulse to configure your status bar."
|
||||
if ($InstallMethod -eq "raw") {
|
||||
Write-Host "Note: installed without git. /pulse update expects a git clone."
|
||||
}
|
||||
125
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/install.sh
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
REPO_SLUG="NoobyGains/claude-pulse"
|
||||
REPO_URL="https://github.com/${REPO_SLUG}.git"
|
||||
RAW_BASE_URL="https://raw.githubusercontent.com/${REPO_SLUG}/main"
|
||||
|
||||
INSTALL_DIR="${CLAUDE_PULSE_DIR:-$HOME/.claude-pulse}"
|
||||
CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
||||
COMMANDS_DIR="${CLAUDE_DIR}/commands"
|
||||
|
||||
INSTALL_METHOD=""
|
||||
|
||||
log() {
|
||||
printf '%s\n' "$*"
|
||||
}
|
||||
|
||||
die() {
|
||||
log "claude-pulse installer: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
has_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
download_file() {
|
||||
src_url="$1"
|
||||
dst_path="$2"
|
||||
|
||||
if has_cmd curl; then
|
||||
curl -fsSL "$src_url" -o "$dst_path"
|
||||
return
|
||||
fi
|
||||
|
||||
if has_cmd wget; then
|
||||
wget -qO "$dst_path" "$src_url"
|
||||
return
|
||||
fi
|
||||
|
||||
die "curl or wget is required when git is unavailable"
|
||||
}
|
||||
|
||||
install_from_raw() {
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
download_file "$RAW_BASE_URL/claude_status.py" "$INSTALL_DIR/claude_status.py"
|
||||
download_file "$RAW_BASE_URL/pulse.md" "$INSTALL_DIR/pulse.md"
|
||||
INSTALL_METHOD="raw"
|
||||
}
|
||||
|
||||
install_repo() {
|
||||
if has_cmd git; then
|
||||
if [ -d "$INSTALL_DIR/.git" ]; then
|
||||
origin_url="$(git -C "$INSTALL_DIR" remote get-url origin 2>/dev/null || true)"
|
||||
origin_lc="$(printf '%s' "$origin_url" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$origin_lc" in
|
||||
*noobygains/claude-pulse|*noobygains/claude-pulse.git)
|
||||
log "Updating existing claude-pulse clone..."
|
||||
git -C "$INSTALL_DIR" pull --ff-only origin main >/dev/null 2>&1 || die "failed to update git clone"
|
||||
INSTALL_METHOD="git"
|
||||
return
|
||||
;;
|
||||
*)
|
||||
die "existing git repo at $INSTALL_DIR has unexpected origin: $origin_url"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -f "$INSTALL_DIR/claude_status.py" ]; then
|
||||
log "Existing non-git install detected, refreshing files..."
|
||||
install_from_raw
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -d "$INSTALL_DIR" ]; then
|
||||
die "directory already exists and is not a claude-pulse install: $INSTALL_DIR"
|
||||
fi
|
||||
|
||||
install_parent="${INSTALL_DIR%/*}"
|
||||
if [ "$install_parent" != "$INSTALL_DIR" ]; then
|
||||
mkdir -p "$install_parent"
|
||||
fi
|
||||
|
||||
log "Cloning claude-pulse..."
|
||||
git clone --depth 1 "$REPO_URL" "$INSTALL_DIR" >/dev/null 2>&1 || die "failed to clone repository"
|
||||
INSTALL_METHOD="git"
|
||||
return
|
||||
fi
|
||||
|
||||
log "git not found, downloading scripts directly..."
|
||||
install_from_raw
|
||||
}
|
||||
|
||||
run_python_install() {
|
||||
if has_cmd python3; then
|
||||
python3 "$INSTALL_DIR/claude_status.py" --install
|
||||
return
|
||||
fi
|
||||
|
||||
if has_cmd python; then
|
||||
python "$INSTALL_DIR/claude_status.py" --install
|
||||
return
|
||||
fi
|
||||
|
||||
die "Python 3 is required. Install Python, then run this installer again."
|
||||
}
|
||||
|
||||
install_pulse_command() {
|
||||
if [ -f "$INSTALL_DIR/pulse.md" ]; then
|
||||
mkdir -p "$COMMANDS_DIR"
|
||||
cp "$INSTALL_DIR/pulse.md" "$COMMANDS_DIR/pulse.md"
|
||||
fi
|
||||
}
|
||||
|
||||
install_repo
|
||||
install_pulse_command
|
||||
run_python_install
|
||||
|
||||
log ""
|
||||
log "claude-pulse installed in: $INSTALL_DIR"
|
||||
log "Restart Claude Code, then run /pulse to configure your status bar."
|
||||
|
||||
if [ "$INSTALL_METHOD" = "raw" ]; then
|
||||
log "Note: installed without git. /pulse update expects a git clone."
|
||||
fi
|
||||
235
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/pulse.md
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
Configure your Claude status bars — themes, colours, animations, peak hours, and more. $ARGUMENTS
|
||||
|
||||
---
|
||||
|
||||
**Finding the script:** Before running any command below, you need the full path to `claude_status.py`. Do this ONCE at the start:
|
||||
|
||||
1. Read `~/.claude/settings.json`. If `statusLine.command` contains `claude_status.py`, extract the full script path from that string.
|
||||
2. If not found, use the Glob tool to search for `**/claude_status.py` inside `~/.claude/plugins/` — pick the result containing `claude-pulse`.
|
||||
3. If neither works, tell the user: "Run `/claude-pulse:setup` first to install the status bar."
|
||||
|
||||
Save the found path as SCRIPT_PATH. Use `python "SCRIPT_PATH"` for all commands below.
|
||||
|
||||
---
|
||||
|
||||
## ROUTING — decide what to do based on $ARGUMENTS
|
||||
|
||||
### Direct commands (skip the menu, run immediately):
|
||||
|
||||
If $ARGUMENTS matches a **theme name** (`default`, `ocean`, `sunset`, `mono`, `neon`, `pride`, `frost`, `ember`, `candy`, `rainbow`):
|
||||
-> Run `python "SCRIPT_PATH" --theme <name>` directly, no menu.
|
||||
-> Confirm: "Theme set to **<name>**. The status line will update on the next refresh."
|
||||
|
||||
If $ARGUMENTS is `config` or `settings`:
|
||||
-> Run `python "SCRIPT_PATH" --config` silently.
|
||||
-> Summarise the settings in your response text (don't show raw ANSI output).
|
||||
|
||||
If $ARGUMENTS is exactly `show` (no parts after it), or `show all`, or `colors`, or `colours`, or `preview`:
|
||||
-> Run TWO separate Bash commands (in parallel):
|
||||
1. `python "SCRIPT_PATH" --show-themes`
|
||||
2. `python "SCRIPT_PATH" --show-colors`
|
||||
-> Show the raw output to the user (coloured ANSI text with live previews).
|
||||
-> After both commands, say ONLY: "Press **Ctrl+O** to expand and see the colours."
|
||||
|
||||
If $ARGUMENTS contains `hide <parts>` or `show <parts>` (with specific parts):
|
||||
-> Run the corresponding `--hide` or `--show` command directly.
|
||||
-> Valid parts: session, weekly, context, timer, weekly_timer, cost, model, branch, heartbeat, activity, update, claude_update, opus, sonnet, effort, worktree, pomodoro, context_warning, staleness, plan, extra, burn_rate, sessions, last_tool, sparkline, runway, status_message, streak, pace, git_drift, files_changed
|
||||
|
||||
If $ARGUMENTS matches `animate <mode>` (where mode is `off`, `rainbow`, `pulse`, `glow`, `shift`, `on`):
|
||||
-> Run `--animate <mode>` directly.
|
||||
-> Explain what the mode does:
|
||||
- **off** — Static, no animation
|
||||
- **rainbow** — Flowing rainbow gradient across the entire bar
|
||||
- **pulse** — Bars cycle through vivid colours each refresh
|
||||
- **glow** — Per-character gradient that shifts across the bar
|
||||
- **shift** — Bright highlight slides across the bar
|
||||
|
||||
If $ARGUMENTS matches `text-color <name>` or `text-colour <name>`:
|
||||
-> Run `--text-color <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `currency <symbol>` (e.g. `currency £`, `currency €`, `currency $`):
|
||||
-> Run `--currency <symbol>` directly.
|
||||
-> Explain: cost is auto-converted from USD using a live exchange rate (cached 24h).
|
||||
|
||||
If $ARGUMENTS matches `bar-size <size>`:
|
||||
-> Run `--bar-size <size>` directly.
|
||||
|
||||
If $ARGUMENTS matches `bar-style <name>` or `style <name>`:
|
||||
-> Run `--bar-style <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `layout <name>`:
|
||||
-> Run `--layout <name>` directly.
|
||||
|
||||
If $ARGUMENTS matches `peak-hours <value>` or `peak <value>`:
|
||||
-> Run `--peak-hours <value>` directly.
|
||||
-> Examples: `peak-hours 13:00-19:00`, `peak-hours off`, `peak-hours on`
|
||||
|
||||
If $ARGUMENTS matches `animation-speed <speed>` or `speed <speed>`:
|
||||
-> Run `--animation-speed <speed>` directly.
|
||||
|
||||
If $ARGUMENTS matches `focus start [minutes]` or `focus stop` or `focus status`:
|
||||
-> Run `--focus <action> [minutes]` directly.
|
||||
-> Default is 25 minutes if no duration given.
|
||||
|
||||
If $ARGUMENTS matches `clock <format>` (where format is `12h` or `24h`):
|
||||
-> Run `--clock-format <format>` directly.
|
||||
|
||||
If $ARGUMENTS matches `preset <name>` or `minimal` or `default preset`:
|
||||
-> Run the corresponding `--preset` command.
|
||||
|
||||
If $ARGUMENTS is `update`:
|
||||
-> Run `python "SCRIPT_PATH" --update` and show the output.
|
||||
|
||||
If $ARGUMENTS is `hooks` or `install-hooks`:
|
||||
-> Run `python "SCRIPT_PATH" --install-hooks` and show the output.
|
||||
-> Remind user to restart Claude Code.
|
||||
|
||||
If $ARGUMENTS is `stats`:
|
||||
-> Run `python "SCRIPT_PATH" --stats` and show the output.
|
||||
|
||||
If $ARGUMENTS is `heatmap`:
|
||||
-> Run `python "SCRIPT_PATH" --heatmap` and show the output.
|
||||
|
||||
### Interactive menu (when $ARGUMENTS is empty, `themes`, `theme`, or `menu`):
|
||||
|
||||
**Step 0 — Quick tips:**
|
||||
|
||||
> **Quick commands:** `/pulse show` preview all themes · `/pulse ocean` set a theme · `/pulse config` see settings · `/pulse update` check for updates · `/pulse focus start` start a focus timer
|
||||
|
||||
Run `python "SCRIPT_PATH" --config` silently to check for updates.
|
||||
|
||||
**Step 1:** Run `python "SCRIPT_PATH" --themes-demo` and show the output.
|
||||
|
||||
**Step 2:** Theme picker (paginated as 3 pages):
|
||||
|
||||
Page 1:
|
||||
```
|
||||
Question: "Pick a theme from the preview above"
|
||||
Options:
|
||||
- "rainbow" — "Full-spectrum flowing colours"
|
||||
- "default" — "Classic green → yellow → red"
|
||||
- "ocean" — "Cool cyan → blue → magenta"
|
||||
- "More themes..." — "See all 10 themes"
|
||||
```
|
||||
|
||||
Page 2 (if "More themes..."):
|
||||
```
|
||||
Options:
|
||||
- "frost" — "Icy blue → steel → white"
|
||||
- "ember" — "Gold → hot orange → red"
|
||||
- "candy" — "Pink → purple → cyan"
|
||||
- "More themes..." — "See neon, sunset, pride, mono"
|
||||
```
|
||||
|
||||
Page 3 (if "More themes..." again):
|
||||
```
|
||||
Options:
|
||||
- "neon" — "Vivid bright green → yellow → red"
|
||||
- "sunset" — "Warm yellow → orange → red"
|
||||
- "pride" — "Violet → green → pink"
|
||||
- "mono" — "White → white → bright white"
|
||||
```
|
||||
|
||||
Apply with `--theme <name>`.
|
||||
|
||||
**Step 3:** Text colour (skip for rainbow):
|
||||
|
||||
Theme-specific recommendations: ocean→cyan, sunset/ember→yellow, frost→cyan, candy→pink, neon→green, pride→violet, default/mono→white.
|
||||
|
||||
```
|
||||
Question: "What colour for labels and percentages?"
|
||||
Options:
|
||||
- "<recommendation> (Recommended)" — "<reason>"
|
||||
- "White" — "Neutral, works with any theme"
|
||||
- "Auto" — "Best match for your theme"
|
||||
```
|
||||
|
||||
Apply with `--text-color <colour>`.
|
||||
|
||||
**Step 4:** Animation:
|
||||
|
||||
```
|
||||
Question: "Choose an animation style"
|
||||
Options:
|
||||
- "Off (Recommended)" — "Static theme colours, clean and simple"
|
||||
- "Rainbow" — "Flowing rainbow gradient"
|
||||
- "Pulse" — "Bars cycle through vivid colours"
|
||||
- "Glow" — "Gradient shifts across the bar"
|
||||
- "Shift" — "Bright highlight slides across"
|
||||
```
|
||||
|
||||
Apply with `--animate <mode>`.
|
||||
|
||||
**Step 5:** Bar size:
|
||||
|
||||
```
|
||||
Question: "How wide should the progress bars be?"
|
||||
Options:
|
||||
- "Large (Recommended)" — "12 characters — detailed bars"
|
||||
- "Medium" — "8 characters — balanced"
|
||||
- "Small" — "4 characters — compact"
|
||||
```
|
||||
|
||||
Apply with `--bar-size <size>`.
|
||||
|
||||
**Step 6:** Currency:
|
||||
|
||||
```
|
||||
Question: "What currency for the cost ticker?"
|
||||
Options:
|
||||
- "$ (USD)" — "US Dollar (base currency)"
|
||||
- "£ (GBP)" — "British Pound (auto-converted)"
|
||||
- "€ (EUR)" — "Euro (auto-converted)"
|
||||
- "Other" — "Type any symbol (¥, ₹, C$, kr, etc.)"
|
||||
```
|
||||
|
||||
Apply with `--currency <symbol>`. Explain: the cost shows what this session would cost at API rates, converted to their currency via live exchange rate.
|
||||
|
||||
**Step 7:** Peak hours:
|
||||
|
||||
```
|
||||
Question: "Enable peak hours indicator? (Anthropic's 2x consumption window)"
|
||||
Options:
|
||||
- "On — 1pm-7pm (Recommended)" — "Default window matching known peak times"
|
||||
- "Custom" — "Set your own peak window"
|
||||
- "Off" — "Don't show peak indicator"
|
||||
```
|
||||
|
||||
If "Custom", ask for start and end time (HH:MM format). Apply with `--peak-hours <start>-<end>`.
|
||||
If "On", apply `--peak-hours on`.
|
||||
If "Off", apply `--peak-hours off`.
|
||||
|
||||
**Step 8:** Clock format:
|
||||
|
||||
```
|
||||
Question: "Clock format for timers?"
|
||||
Options:
|
||||
- "12h" — "Fri 5pm"
|
||||
- "24h" — "Fri 17:00"
|
||||
```
|
||||
|
||||
Apply with `--clock-format <12h|24h>`.
|
||||
|
||||
**Step 9:** Live heartbeat hook:
|
||||
|
||||
```
|
||||
Question: "Install the live heartbeat hook? (shows tool counter during active work)"
|
||||
Options:
|
||||
- "Yes (Recommended)" — "Adds [/] 42 tools 5m to your status bar"
|
||||
- "No" — "Skip — you can install later with /pulse hooks"
|
||||
```
|
||||
|
||||
If "Yes", run `python "SCRIPT_PATH" --install-hooks`. Remind to restart Claude Code.
|
||||
|
||||
**Step 10:** Confirm everything:
|
||||
"All set! Your status bar is configured with **<theme>**, **<animation>** animation, **<currency>** cost tracking, and peak hours **<on/off>**. It updates on every interaction."
|
||||
|
||||
If hooks were installed: "Restart Claude Code to activate the live heartbeat."
|
||||
|
||||
---
|
||||
|
||||
## DISPLAY RULES
|
||||
|
||||
- After any change, tell the user it will update on the next refresh.
|
||||
- When running `--config`, summarise — don't show raw ANSI.
|
||||
- Be brief and enthusiastic.
|
||||
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/rainbow.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/screenshot.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
claude/.claude/plugins/cache/claude-pulse/claude-pulse/3.0.0/themes.png
vendored
Normal file
|
After Width: | Height: | Size: 57 KiB |