@clawhub-miluer-tcq-3cfbef82b7
Configure Claude Code statuslines / 状态栏. Use this skill whenever the user wants to install, set up, preview, switch, clean up, customize, restore, or fix a C...
---
name: cc-statusline
description: >-
Configure Claude Code statuslines / 状态栏. Use this skill whenever the user wants to install, set up, preview, switch, clean up, customize, restore, or fix a Claude Code statusline: choose Full / Standard / Minimal / Developer presets, fine-tune an existing preset, generate-only or activate a custom 1 / 2 / 3-line layout with modules like model / git / context / token / cost, change theme or icon style, restore the default statusline while keeping scripts, or troubleshoot a broken statusLine command on Windows, macOS, or Linux. 也适用于安装、预览、切换预设、微调、美化、恢复默认、排障、自定义。 Only for Claude Code, not shell prompts, VS Code, Windows taskbar, web status bars, or Claude Desktop.
---
# cc-statusline / Claude Code 状态栏助手
## Purpose / 用途
Use this skill to help users preview, install, customize, switch, troubleshoot, and uninstall Claude Code statuslines.
当用户想预览、安装、自定义、切换、排障或卸载 Claude Code 状态栏时,使用这个 skill。
This skill is designed for:
这个 skill 主要适用于:
- preset installation / 安装预设状态栏
- interactive custom generation / 交互式自定义生成
- preset-based fine-tuning / 基于预设微调
- theme and icon switching / 切换主题与图标风格
- layout cleanup and readability improvement / 优化布局与可读性
- uninstall or restore-default workflows / 卸载或恢复默认状态栏
- Windows, macOS, Linux setup support / Windows、macOS、Linux 三端安装支持
## Runtime map / 运行路径映射
Treat this folder as the skill base directory.
把当前目录视为 skill 基目录。
Use these relative paths from the skill directory:
从 skill 目录出发,使用这些相对路径:
- `scripts/generate_custom_statusline.sh` → generate a custom runtime script / 生成自定义状态栏脚本
- `scripts/activate_preset_statusline.sh` → install or switch a preset / 安装或切换预设
- `scripts/activate_custom_statusline.sh` → activate a generated custom script / 启用生成好的自定义脚本
- `scripts/uninstall_statusline.sh` → remove only the `statusLine` config / 只移除 `statusLine` 配置
Default paths:
默认路径:
- preset target / 预设脚本:`~/.claude/statusline.sh`
- custom target / 自定义脚本:`~/.claude/statusline.custom.sh`
- settings / 设置文件:`~/.claude/settings.json`
- state snapshot / 状态快照:`~/.claude/cc-statusline-state.json`
## Language behavior / 语言行为
- Match the user’s input language when leading the conversation.
- Keep key labels bilingual when helpful, especially for preset names, themes, icon styles, and install steps.
- 根据用户输入语言切换主要交流语言。
- 对关键名词保留双语,尤其是预设名、主题名、图标风格、安装步骤。
## Intent routing / 意图分流
Map the request into one of these flows:
将请求归入以下流程之一:
- **Install preset / 安装预设**
- **Customize from scratch / 从零自定义**
- **Customize from a preset / 基于预设微调**
- **Beautify or optimize existing statusline / 美化或优化现有状态栏**
- **Uninstall or restore default / 卸载或恢复默认**
- **Troubleshoot installation / 排查安装问题**
## Trigger emphasis / 触发重点
Trigger this skill aggressively when the user is clearly talking about Claude Code and any of these intents:
当用户明确在说 Claude Code,并且出现以下任一意图时,应积极触发这个 skill:
- install or set up a statusline / 安装或配置状态栏
- choose or switch a preset / 选择或切换预设
- generate a custom layout / 生成自定义布局
- switch themes or icon styles / 切换主题或图标风格
- beautify, optimize, simplify, or improve readability / 美化、优化、精简、提升可读性
- disable, uninstall, or restore default behavior / 禁用、卸载、恢复默认
- troubleshoot a broken `statusLine` command or failed install / 排查损坏的 `statusLine` 命令或失败的安装
Do not trigger for shell prompts, terminal themes, Windows taskbar changes, VS Code status bars, or general web UI status bars unless the user clearly ties the request back to Claude Code.
除非用户明确把需求指向 Claude Code,否则不要把 shell prompt、终端主题、Windows 任务栏、VS Code 状态栏或网页状态栏误判为本 skill 的触发场景。
## Ask only what is missing / 只问缺失信息
Prioritize questions in this order:
按这个顺序补问:
1. preset vs custom / 预设还是自定义
2. modules / 模块开关
3. line count / 行数(1/2/3)
4. theme / 主题
5. icon style / 图标风格
6. target path / 目标路径
7. activate now / 是否立即启用
Prefer grouped module presentation:
模块优先按分组展示:
- Base group / 基础信息
- Environment group / 环境信息
- Metrics group / 统计信息
Read `references/modules.md` when you need the canonical module list.
需要标准模块清单时读取 `references/modules.md`。
## Presets / 预设
Available presets:
可用预设:
- `Full / 完整版`
- `Standard / 标准版`
- `Minimal / 极简版`
- `Developer / 开发者版`
Preset goals:
预设定位:
- **Full / 完整版**: closest to the current full Miluer-style information density / 最接近当前 Miluer 风格的完整信息密度
- **Standard / 标准版**: balanced for daily use / 适合日常使用
- **Minimal / 极简版**: lowest visual noise / 最低视觉干扰
- **Developer / 开发者版**: emphasizes git and token visibility / 强调 Git 与 Token 可见性
Use `presets/*.json` for line count and module summaries before presenting options.
在展示选项前,使用 `presets/*.json` 获取行数与模块摘要。
## Preview rule / 预览规则
Always show a concise preview before writing files or changing `statusLine.command`.
在写文件或改 `statusLine.command` 前,始终先给出简洁预览。
Use this structure:
使用这个结构:
```text
Statusline preview / 状态栏预览
- Mode / 模式: preset | custom
- Preset / 预设: <preset or custom>
- Lines / 行数: <1|2|3>
- Line 1 / 第 1 行: <modules>
- Line 2 / 第 2 行: <modules or empty>
- Line 3 / 第 3 行: <modules or empty>
- Theme / 主题: <theme>
- Icon style / 图标风格: <icon style>
- Target / 目标文件: <path>
- Backup / 备份: <path or not needed>
- settings.json change / 设置改动: only statusLine
- Activation / 启用方式: now | generate only
```
If the user already asked for one-click install and the context is clear, preview first and then execute.
如果用户已经明确要求一键安装且上下文清晰,先预览再执行。
## Execution flows / 执行流程
### A. Install preset / 安装预设
Use this flow when the user wants a ready-made statusline.
当用户要直接套用预设时使用。
1. If the preset is not specified, offer the 4 presets with short summaries.
2. Resolve theme, icon style, and target path.
3. Preview the exact result.
4. Run:
```bash
bash "scripts/activate_preset_statusline.sh" "<preset>" "<theme>" "<icon_style>" "<target_path>"
```
Default target path:
默认目标路径:
```bash
~/.claude/statusline.sh
```
After the command finishes, report:
命令完成后汇报:
- active command / 当前启用命令
- target file / 目标文件
- backup file / 备份文件
- state snapshot / 状态快照文件
- that only `statusLine` was changed / 仅修改了 `statusLine`
### B. Customize from scratch / 从零自定义
Use this when the user wants grouped module selection or a fresh layout.
当用户要按模块分组自由搭配时使用。
1. Read `references/modules.md` if needed.
2. Collect modules per line.
3. Determine line count.
4. Determine theme, icon style, target path, and whether to activate now.
5. Preview the custom layout.
6. Generate the custom script with:
```bash
bash "scripts/generate_custom_statusline.sh" "<custom_path>" "<line_1_csv>" "<line_2_csv_or_->" "<line_3_csv_or_->" "<theme>" "<icon_style>"
```
Notes:
说明:
- Use comma-separated module ids such as `model,modes,active`.
- For unused lines, pass `-`.
- 使用逗号分隔的模块 id,例如 `model,modes,active`。
- 对不使用的行传入 `-`。
Examples:
示例:
```bash
bash "scripts/generate_custom_statusline.sh" "$HOME/.claude/statusline.custom.sh" "model,modes,active" "cwd,git,context" "ctx_tokens,sum_tokens,duration,cost" "ocean" "developer"
```
One-line custom example:
单行自定义示例:
```bash
bash "scripts/generate_custom_statusline.sh" "$HOME/.claude/statusline.custom.sh" "model,active,cost" "-" "-" "mono" "minimal"
```
If the user wants immediate activation, then run:
如果用户要立即启用,再运行:
```bash
bash "scripts/activate_custom_statusline.sh" "<custom_path>" "<theme>" "<icon_style>"
```
If the user only asked to generate or preview, stop after generation and explain how to activate later.
如果用户只要求生成或预览,生成后停止,并说明后续如何手动启用。
### C. Customize from a preset / 基于预设微调
Use the preset as the starting point, then adjust lines/modules/theme/icons.
以预设为起点,再调整行数、模块、主题、图标。
1. Load the selected preset summary from `presets/*.json`.
2. Present it as the starting layout.
3. Apply the user’s module or line-count changes.
4. Generate with `scripts/generate_custom_statusline.sh`.
5. Activate with `scripts/activate_custom_statusline.sh` only if the user wants the new custom script live now.
### D. Beautify or optimize / 美化或优化
Choose the smallest useful change.
优先选最小但有效的变更。
Use this decision rule:
使用这个判断顺序:
1. **Theme or icon only / 只改主题或图标** → re-run preset activation with the same preset and new style if the user is still using a preset layout.
2. **Modules or line count changed / 改模块或行数** → generate a custom script.
3. **Unclear request / 需求不明确** → offer 2-3 concrete options instead of asking broad questions.
### E. Uninstall or restore default / 卸载或恢复默认
Run:
```bash
bash "scripts/uninstall_statusline.sh"
```
Then explain:
然后说明:
- only the `statusLine` entry was removed / 只移除了 `statusLine`
- generated script files were kept / 已保留生成的脚本文件
- the previous snapshot remains in `~/.claude/cc-statusline-state.json` if available / 如存在,旧配置快照仍保留在 `~/.claude/cc-statusline-state.json`
### F. Troubleshoot installation / 排查安装问题
When install or activation fails, inspect in this order:
安装或启用失败时,按这个顺序排查:
1. target script exists / 目标脚本是否存在
2. `~/.claude/settings.json` contains the expected `statusLine` / `settings.json` 是否写入预期 `statusLine`
3. jq availability / jq 是否可用
4. whether an old foreign `statusLine` blocked overwrite / 是否被旧的外部配置拦住
5. whether re-running the wrapper is enough / 是否只需重跑脚本
Prefer re-running the wrapper script over telling the user to edit JSON manually.
优先重跑封装脚本,而不是直接让用户手改 JSON。
Only fall back to manual repair when automation fails.
只有自动流程失败时再给手动修复步骤。
## Settings safety / 设置安全规则
- Only touch the `statusLine` field.
- Do not rewrite unrelated settings.
- If an existing `statusLine` looks foreign, ask before replacement.
- Do not delete generated scripts unless the user explicitly requests deletion.
- 只修改 `statusLine`。
- 不改动无关设置。
- 如果现有 `statusLine` 看起来不是本 skill 生成的,替换前先询问。
- 除非用户明确要求,否则不要删除已生成脚本。
## Response style / 回复风格
- Be concise but structured.
- Summarize the selected options clearly.
- Preview before writing.
- After running commands, report what changed and where.
- Keep key choices bilingual.
- 简洁但结构清晰。
- 清楚总结已选项。
- 写入前先预览。
- 执行后说明改了什么、改到哪里。
- 关键选项保留双语。
## Post-action summary / 执行后总结
After installation, generation, activation, or uninstall, end with a short summary like:
安装、生成、启用或卸载后,用类似下面的格式收尾:
```text
Done / 已完成
- Generated / 生成: <file or not needed>
- Updated / 更新: ~/.claude/settings.json (statusLine only)
- Backup / 备份: <path or none>
- Snapshot / 快照: ~/.claude/cc-statusline-state.json
- Active command / 当前命令: <statusLine.command or not active>
- Next step / 下一步: <optional suggestion>
```
FILE:README.en.md
# cc-statusline
> Claude Code Statusline Assistant
>
> 中文说明: [README.md](README.md)
## Project Description / 项目描述
- English: `cc-statusline` is a Claude Code statusline skill for installing, switching, previewing, fine-tuning, and restoring statuslines with bilingual triggering, preset installs, custom layouts, theme / icon switching, and Windows / macOS / Linux support.
- 中文:`cc-statusline` 是一个面向 Claude Code 的状态栏 skill,用来安装、切换、预览、微调和恢复状态栏,支持双语触发、预设安装、自定义布局、主题 / 图标切换,以及 Windows / macOS / Linux 三平台。
A bilingual Claude Code statusline skill for preset installation, preview-first activation, interactive customization, theme / icon switching, and cross-platform support on Windows, macOS, and Linux.
## Install this skill
### Option 1: Paste the GitHub link to AI and ask it to install the skill (best for normal users)
Send this repository URL to an AI agent that can operate inside Claude Code and ask it to install the skill:
```text
https://github.com/Miluer-tcq/cc-statusline
```
Copy-ready prompt:
```text
Please install this Claude Code skill for me:
https://github.com/Miluer-tcq/cc-statusline
Install target: ~/.claude/skills/cc-statusline
After installation, tell me how to trigger it.
```
Notes:
- The install target is `~/.claude/skills/cc-statusline`
- This installs a **skill directory**, not a plugin
- After installation, Claude Code can trigger it with natural language
### Option 2: Install manually from the GitHub repository
The repository is now flattened, so the **repository root is the skill root**. For manual installation, copy the runtime files into `~/.claude/skills/cc-statusline`:
```bash
git clone https://github.com/Miluer-tcq/cc-statusline
mkdir -p ~/.claude/skills/cc-statusline
cp -r cc-statusline/SKILL.md cc-statusline/scripts cc-statusline/presets cc-statusline/themes cc-statusline/icons cc-statusline/references ~/.claude/skills/cc-statusline/
```
## How to use it after installation
After installing, you can say things like:
- `Install the Full / 完整版 statusline for me`
- `Switch me to the Developer / 开发者版 statusline`
- `Generate a 2-line custom statusline with the ocean theme and developer icons`
- `Uninstall the statusline and restore the default one`
If your current session does not notice the new skill yet, restart the Claude Code session.
## Features
- bilingual trigger coverage for Chinese and English requests
- one-click preset installation
- grouped module-based custom layouts
- custom generation from scratch or from a preset
- 1 / 2 / 3 line layouts
- theme and icon style switching
- backup of the target script to `<target>.bak`
- previous `statusLine` snapshot saved to `~/.claude/cc-statusline-state.json`
- updates only the `statusLine` field in `~/.claude/settings.json`
- uninstall removes only `statusLine` and keeps generated scripts on disk
## Current repository layout
The repository has been flattened:
- the repository root is now the installable `cc-statusline` skill root
- `SKILL.md` is the skill entry point
- `scripts/`, `presets/`, `themes/`, `icons/`, and `references/` are runtime assets
- `assets/screenshots/` are GitHub presentation assets and are not required for runtime
- the `.skill` package can be generated on demand and distributed as a release asset instead of staying in the repository
## Manual use of bundled skill scripts
If the skill is already installed, you can also call its scripts directly.
### 1. Activate a preset statusline
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh full aurora classic
```
What the preset install flow does:
- installs or reuses `jq`
- backs up the target script to `<target>.bak`
- preserves the previous `statusLine` value in `~/.claude/cc-statusline-state.json`
- writes the runtime script to `~/.claude/statusline.sh` by default
- updates only the `statusLine` field in `~/.claude/settings.json`
- asks before replacing a foreign `statusLine` configuration
### 2. Generate a custom statusline
Generate a three-line custom layout:
```bash
bash ~/.claude/skills/cc-statusline/scripts/generate_custom_statusline.sh \
"$HOME/.claude/statusline.custom.sh" \
"model,modes,active" \
"cwd,git,context" \
"ctx_tokens,sum_tokens,duration,cost" \
"ocean" \
"developer"
```
Generate a one-line custom layout:
```bash
bash ~/.claude/skills/cc-statusline/scripts/generate_custom_statusline.sh \
"$HOME/.claude/statusline.custom.sh" \
"model,active,cost" \
"-" \
"-" \
"mono" \
"minimal"
```
Notes:
- use comma-separated module ids per line
- pass `-` for an unused line
- the generator prints a compact summary of the final layout
Activate the generated custom script:
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_custom_statusline.sh "$HOME/.claude/statusline.custom.sh" ocean developer
```
Switch back to a preset later:
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh full aurora classic
```
### 3. Uninstall / restore default behavior
```bash
bash ~/.claude/skills/cc-statusline/scripts/uninstall_statusline.sh
```
This removes only the `statusLine` field from `~/.claude/settings.json`.
Generated script files stay on disk unless the user explicitly wants them removed.
### 4. `.skill` packaging
This repository now supports skill-first distribution:
- copy the root skill files into `~/.claude/skills/cc-statusline`
- generate a `.skill` package from the repository root only when preparing a release
- the packaged `.skill` file does not need to stay checked into the repository
## Presets
- `Full / 完整版` — closest to the current full Miluer-style layout
- `Standard / 标准版` — balanced for daily use
- `Minimal / 极简版` — lowest visual noise
- `Developer / 开发者版` — emphasizes git state and token visibility
## Themes
- `Aurora / 极光`
- `Sunset / 日落`
- `Ocean / 海洋`
- `Mono / 单色`
## Icon styles
- `classic / 经典`
- `minimal / 极简`
- `developer / 开发者`
## Customization model
The skill supports:
- selecting a preset directly
- starting from scratch with grouped module selection
- starting from a preset and fine-tuning modules
- choosing 1 / 2 / 3 line layouts
- choosing an existing theme first, then refining colors
- switching icon styles
- generating `~/.claude/statusline.custom.sh` before activation
Canonical module groups are documented in `references/modules.md`.
Trigger phrase examples are documented in `references/trigger-phrases.md`.
## Screenshots
### Preset selection / 预设选择

### Custom layout preview / 自定义布局预览

### Themes and icon styles / 主题与图标风格

### Installed statusline examples / 安装后状态栏示例

### Cross-platform install examples / 三平台安装示例

FILE:README.md
# cc-statusline
> Claude Code 状态栏助手
>
> English README: [README.en.md](README.en.md)
## 项目描述 / Project Description
- 中文:`cc-statusline` 是一个面向 Claude Code 的状态栏 skill,用来安装、切换、预览、微调和恢复状态栏,支持双语触发、预设安装、自定义布局、主题 / 图标切换,以及 Windows / macOS / Linux 三平台。
- English: `cc-statusline` is a Claude Code statusline skill for installing, switching, previewing, fine-tuning, and restoring statuslines with bilingual triggering, preset installs, custom layouts, theme / icon switching, and Windows / macOS / Linux support.
一个支持中英文触发的 Claude Code 状态栏 skill,提供预设安装、先预览后启用、交互式自定义、主题 / 图标切换,以及 Windows、macOS、Linux 三平台支持。
## 安装这个 skill
### 方式 1:把 GitHub 链接发给 AI,让它自动安装(推荐给普通用户)
把下面这个仓库链接直接发给支持 Claude Code 文件操作的 AI,然后让它安装这个 skill:
```text
https://github.com/Miluer-tcq/cc-statusline
```
可直接复制的提示词:
```text
请帮我安装这个 Claude Code skill:
https://github.com/Miluer-tcq/cc-statusline
安装目标:~/.claude/skills/cc-statusline
安装完成后告诉我如何触发它。
```
说明:
- 安装目标是 `~/.claude/skills/cc-statusline`
- 安装的是 **skill 目录**,不是 plugin
- 安装完成后,Claude Code 就能按自然语言触发这个 skill
### 方式 2:通过 GitHub 仓库手动安装
当前仓库已经扁平化,**仓库根目录就是 skill 根目录**。手动安装时,把运行所需文件复制到 `~/.claude/skills/cc-statusline`:
```bash
git clone https://github.com/Miluer-tcq/cc-statusline
mkdir -p ~/.claude/skills/cc-statusline
cp -r cc-statusline/SKILL.md cc-statusline/scripts cc-statusline/presets cc-statusline/themes cc-statusline/icons cc-statusline/references ~/.claude/skills/cc-statusline/
```
## 安装后如何使用
安装完成后,可以直接在 Claude Code 里输入:
- `帮我一键安装 Full / 完整版 状态栏`
- `帮我切换到 Developer / 开发者版 状态栏`
- `帮我生成一个 2 行自定义状态栏,主题用 ocean,图标用 developer`
- `卸载状态栏,恢复默认状态栏`
如果当前会话还没识别到新 skill,重开一次 Claude Code 会话即可。
## 功能特性
- 覆盖中英文触发表达
- 支持一键安装预设状态栏
- 支持按模块分组生成自定义布局
- 支持从零自定义或从预设微调
- 支持 1 / 2 / 3 行布局
- 支持主题与图标风格切换
- 覆盖安装前会将目标脚本备份到 `<目标路径>.bak`
- 会把旧的 `statusLine` 快照保存到 `~/.claude/cc-statusline-state.json`
- 只修改 `~/.claude/settings.json` 里的 `statusLine` 字段
- 卸载时只移除 `statusLine`,默认保留已生成脚本
## 当前仓库结构
当前仓库已经收敛为扁平结构:
- 根目录就是可安装的 `cc-statusline` skill 根目录
- `SKILL.md` 是 skill 入口
- `scripts/`、`presets/`、`themes/`、`icons/`、`references/` 是运行时资源
- `assets/screenshots/` 是 GitHub 展示资源,不影响 skill 运行
- `.skill` 打包文件可按需生成并作为 release 附件分发,不需要常驻仓库
## 手动调用 skill 内脚本
如果你已经安装了 skill,也可以直接调用 skill 目录里的脚本。
### 1. 启用预设状态栏
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh full aurora classic
```
预设安装流程会:
- 安装或复用 `jq`
- 将目标脚本备份到 `<目标路径>.bak`
- 把旧的 `statusLine` 值保存到 `~/.claude/cc-statusline-state.json`
- 默认把运行时脚本写入 `~/.claude/statusline.sh`
- 仅修改 `~/.claude/settings.json` 里的 `statusLine` 字段
- 如果检测到外部已有 `statusLine` 配置,会先询问再覆盖
### 2. 生成自定义状态栏
生成三行自定义布局:
```bash
bash ~/.claude/skills/cc-statusline/scripts/generate_custom_statusline.sh \
"$HOME/.claude/statusline.custom.sh" \
"model,modes,active" \
"cwd,git,context" \
"ctx_tokens,sum_tokens,duration,cost" \
"ocean" \
"developer"
```
生成单行自定义布局:
```bash
bash ~/.claude/skills/cc-statusline/scripts/generate_custom_statusline.sh \
"$HOME/.claude/statusline.custom.sh" \
"model,active,cost" \
"-" \
"-" \
"mono" \
"minimal"
```
说明:
- 每一行使用逗号分隔的模块 id
- 不使用的行传 `-`
- 生成器会输出一份简洁的最终布局摘要
启用生成好的自定义脚本:
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_custom_statusline.sh "$HOME/.claude/statusline.custom.sh" ocean developer
```
后续如需切回预设:
```bash
bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh full aurora classic
```
### 3. 卸载 / 恢复默认行为
```bash
bash ~/.claude/skills/cc-statusline/scripts/uninstall_statusline.sh
```
该脚本只会移除 `~/.claude/settings.json` 中的 `statusLine` 字段。
除非用户明确要求,否则不会删除已生成的脚本文件。
### 4. `.skill` 打包
当前仓库已经支持以 skill 为核心的分发方式:
- 把仓库根目录中的 skill 文件复制到 `~/.claude/skills/cc-statusline`
- 需要发 release 时,再从当前仓库根目录临时打包为 `.skill`
- `.skill` 成品不需要常驻仓库,可作为 release 附件单独分发
## 预设
- `Full / 完整版` — 最接近当前 Miluer 风格的完整布局
- `Standard / 标准版` — 适合日常使用的均衡布局
- `Minimal / 极简版` — 视觉干扰最低
- `Developer / 开发者版` — 强调 Git 状态与 Token 可见性
## 主题
- `Aurora / 极光`
- `Sunset / 日落`
- `Ocean / 海洋`
- `Mono / 单色`
## 图标风格
- `classic / 经典`
- `minimal / 极简`
- `developer / 开发者`
## 自定义方式
这个 skill 支持:
- 直接选择预设
- 从零开始按分组选择模块
- 先选预设再微调模块
- 选择 1 / 2 / 3 行布局
- 优先选择现有主题,再做颜色微调
- 切换图标风格
- 先生成 `~/.claude/statusline.custom.sh`,再决定是否启用
标准模块分组见 `references/modules.md`。
触发词示例见 `references/trigger-phrases.md`。
## 截图
### 预设选择 / Preset selection

### 自定义布局预览 / Custom layout preview

### 主题与图标风格 / Themes and icon styles

### 安装后的状态栏示例 / Installed statusline examples

### 三平台安装示例 / Cross-platform install examples

FILE:assets/screenshots/cross-platform-install.svg
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-labelledby="title desc">
<title>Cross-platform install examples / 三平台安装示例</title>
<desc>Windows, macOS, Linux, manual install, and AI link install flows.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0b1020" />
<stop offset="55%" stop-color="#10192b" />
<stop offset="100%" stop-color="#1e293b" />
</linearGradient>
</defs>
<style>
.bg { fill: url(#bg); }
.panel { fill: #111827; stroke: #243041; stroke-width: 1.2; }
.terminal { fill: #0b1020; stroke: #334155; stroke-width: 1.2; }
.title { fill: #f8fafc; font: 700 34px 'Segoe UI', 'Inter', Arial, sans-serif; }
.subtitle { fill: #94a3b8; font: 500 17px 'Segoe UI', 'Inter', Arial, sans-serif; }
.section { fill: #e2e8f0; font: 700 21px 'Segoe UI', 'Inter', Arial, sans-serif; }
.body { fill: #dbe4f0; font: 500 18px 'Segoe UI', 'Inter', Arial, sans-serif; }
.small { fill: #94a3b8; font: 500 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.mono-small { fill: #dbe4f0; font: 500 17px 'Cascadia Code', Consolas, Menlo, monospace; }
.accent-text { fill: #7dd3fc; font: 700 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
</style>
<rect class="bg" x="0" y="0" width="1600" height="900" rx="0"/>
<rect x="48" y="38" width="1504" height="824" rx="28" fill="rgba(15,23,42,0.65)" stroke="#334155" stroke-width="1.2"/>
<text class="title" x="90" y="102">Cross-platform install examples / 三平台安装示例</text>
<text class="subtitle" x="90" y="136">Windows, macOS, Linux, manual install, and AI link install flows.</text>
<rect class="panel" x="90" y="184" width="450" height="286" rx="24"/>
<rect x="90" y="184" width="450" height="10" rx="24" fill="#60a5fa"/>
<text class="section" x="116" y="232">Windows</text>
<text class="small" x="116" y="261">Preset install example / 预设安装示例</text>
<text class="body" x="116" y="302">bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh</text>
<text class="body" x="116" y="336">Backup: ~/.claude/statusline.sh.bak</text>
<text class="body" x="116" y="370">Updates only the statusLine field / 仅修改 statusLine</text>
<text class="body" x="116" y="404">Preview first when invoked via skill / 通过 skill 时先预览</text>
<rect class="panel" x="575" y="184" width="450" height="286" rx="24"/>
<rect x="575" y="184" width="450" height="10" rx="24" fill="#a78bfa"/>
<text class="section" x="601" y="232">macOS</text>
<text class="small" x="601" y="261">Preset install example / 预设安装示例</text>
<text class="body" x="601" y="302">bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh</text>
<text class="body" x="601" y="336">Writes ~/.claude/statusline.sh by default</text>
<text class="body" x="601" y="370">Reuses jq if available / 优先复用 jq</text>
<text class="body" x="601" y="404">Same preset/theme/icon arguments / 同一套参数</text>
<rect class="panel" x="1060" y="184" width="450" height="286" rx="24"/>
<rect x="1060" y="184" width="450" height="10" rx="24" fill="#34d399"/>
<text class="section" x="1086" y="232">Linux</text>
<text class="small" x="1086" y="261">Preset install example / 预设安装示例</text>
<text class="body" x="1086" y="302">bash ~/.claude/skills/cc-statusline/scripts/activate_preset_statusline.sh</text>
<text class="body" x="1086" y="336">Keeps previous snapshot in cc-statusline-state.json</text>
<text class="body" x="1086" y="370">No unrelated settings touched / 不改无关设置</text>
<text class="body" x="1086" y="404">Works with preset and custom flows / 预设与 custom 通用</text>
<rect class="terminal" x="90" y="524" width="1420" height="210" rx="24"/>
<rect x="90" y="524" width="1420" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="114" cy="546" r="6" fill="#fb7185"/>
<circle cx="136" cy="546" r="6" fill="#fbbf24"/>
<circle cx="158" cy="546" r="6" fill="#34d399"/>
<text class="small" x="186" y="551">Manual install + AI link install / 手动安装 + AI 链接安装</text>
<rect x="90" y="568" width="1420" height="6" fill="#f59e0b"/>
<text class="mono-small" x="114" y="612">git clone https://github.com/Miluer-tcq/cc-statusline</text>
<text class="mono-small" x="114" y="643">cp -r cc-statusline/{SKILL.md,scripts,presets,themes,icons,references} ~/.claude/skills/cc-statusline</text>
<text class="mono-small" x="114" y="674">Paste this URL to AI and ask it to install the skill automatically:</text>
<text class="mono-small" x="114" y="705">https://github.com/Miluer-tcq/cc-statusline</text>
<text class="accent-text" x="90" y="780">The release flow now supports self-contained skill install, manual install, and AI link install / 现已支持自包含 skill 安装、手动安装与 AI 链接安装。</text>
</svg>
FILE:assets/screenshots/custom-layout-preview.svg
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-labelledby="title desc">
<title>Custom layout preview / 自定义布局预览</title>
<desc>Grouped module selection, preview-first flow, and generate-only custom output.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0b1020" />
<stop offset="55%" stop-color="#10192b" />
<stop offset="100%" stop-color="#1e293b" />
</linearGradient>
</defs>
<style>
.bg { fill: url(#bg); }
.panel { fill: #111827; stroke: #243041; stroke-width: 1.2; }
.panel-soft { fill: #0f172a; stroke: #243041; stroke-width: 1.2; }
.panel-muted { fill: #0b1220; stroke: #1f2937; stroke-width: 1.2; }
.terminal { fill: #0b1020; stroke: #334155; stroke-width: 1.2; }
.title { fill: #f8fafc; font: 700 34px 'Segoe UI', 'Inter', Arial, sans-serif; }
.subtitle { fill: #94a3b8; font: 500 17px 'Segoe UI', 'Inter', Arial, sans-serif; }
.section { fill: #e2e8f0; font: 700 21px 'Segoe UI', 'Inter', Arial, sans-serif; }
.body { fill: #dbe4f0; font: 500 18px 'Segoe UI', 'Inter', Arial, sans-serif; }
.small { fill: #94a3b8; font: 500 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.mono { fill: #e5edf7; font: 600 19px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-small { fill: #dbe4f0; font: 500 17px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-tiny { fill: #cbd5e1; font: 500 15px 'Cascadia Code', Consolas, Menlo, monospace; }
.chip { fill: #0f172a; stroke: #334155; stroke-width: 1; }
.chip-text { fill: #cbd5e1; font: 600 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.badge { fill: #1d4ed8; }
.badge-text { fill: #eff6ff; font: 700 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.accent-text { fill: #7dd3fc; font: 700 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.green { fill: #86efac; }
.yellow { fill: #fde68a; }
.orange { fill: #fdba74; }
.pink { fill: #f9a8d4; }
.blue { fill: #93c5fd; }
.muted { fill: #64748b; }
</style>
<rect class="bg" x="0" y="0" width="1600" height="900" rx="0"/>
<rect x="48" y="38" width="1504" height="824" rx="28" fill="rgba(15,23,42,0.65)" stroke="#334155" stroke-width="1.2"/>
<text class="title" x="90" y="102">Custom layout preview / 自定义布局预览</text>
<text class="subtitle" x="90" y="136">Grouped module selection, preview-first flow, and generate-only custom output.</text>
<rect class="panel-soft" x="90" y="182" width="500" height="636" rx="24"/>
<text class="section" x="118" y="226">Grouped modules / 模块分组</text>
<text class="small" x="118" y="254">Select modules by group, then map them into 1 / 2 / 3 lines.</text>
<rect x="118" y="292" width="118" height="34" rx="17" fill="#132238" stroke="#3b82f6" stroke-width="1"/><text x="177.0" y="314" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">Base / 基础</text>
<rect x="248" y="292" width="166" height="34" rx="17" fill="#11261f" stroke="#10b981" stroke-width="1"/><text x="331.0" y="314" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">Environment / 环境</text>
<rect x="428" y="292" width="136" height="34" rx="17" fill="#2b1d16" stroke="#f59e0b" stroke-width="1"/><text x="496.0" y="314" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">Metrics / 统计</text>
<rect x="118" y="348" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="177.0" y="370" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">model</text>
<rect x="248" y="348" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="307.0" y="370" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">modes</text>
<rect x="378" y="348" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="437.0" y="370" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">active</text>
<rect x="118" y="394" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="177.0" y="416" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">cwd</text>
<rect x="248" y="394" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="307.0" y="416" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">git</text>
<rect x="378" y="394" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="437.0" y="416" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">context</text>
<rect x="118" y="440" width="132" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="184.0" y="462" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">ctx_tokens</text>
<rect x="264" y="440" width="132" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="330.0" y="462" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">sum_tokens</text>
<rect x="410" y="440" width="118" height="34" rx="17" fill="#0f172a" stroke="#334155" stroke-width="1"/><text x="469.0" y="462" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">cost</text>
<text class="body" x="118" y="516">Example choice / 示例组合</text>
<text class="mono-small" x="118" y="552">Line 1 → model, active, cost</text>
<text class="mono-small" x="118" y="584">Line 2 → cwd, git, context</text>
<text class="mono-small" x="118" y="616">Line 3 → -</text>
<rect x="118" y="660" width="120" height="34" rx="17" fill="#0d2730" stroke="#06b6d4" stroke-width="1"/><text x="178.0" y="682" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">Ocean / 海洋</text>
<rect x="250" y="660" width="152" height="34" rx="17" fill="#1f2937" stroke="#64748b" stroke-width="1"/><text x="326.0" y="682" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">developer icons</text>
<rect x="414" y="660" width="128" height="34" rx="17" fill="#231c38" stroke="#a855f7" stroke-width="1"/><text x="478.0" y="682" text-anchor="middle" style="fill:#cbd5e1;font:600 14px Segoe UI, Inter, Arial, sans-serif;">generate only</text>
<rect class="terminal" x="636" y="182" width="874" height="304" rx="24"/>
<rect x="636" y="182" width="874" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="660" cy="204" r="6" fill="#fb7185"/>
<circle cx="682" cy="204" r="6" fill="#fbbf24"/>
<circle cx="704" cy="204" r="6" fill="#34d399"/>
<text class="small" x="732" y="209">Statusline preview / 状态栏预览</text>
<rect x="636" y="226" width="874" height="6" fill="#22d3ee"/>
<text class="mono-small" x="660" y="270">- Mode / 模式: custom</text>
<text class="mono-small" x="660" y="301">- Preset / 预设: custom (from scratch)</text>
<text class="mono-small" x="660" y="332">- Lines / 行数: 2</text>
<text class="mono-small" x="660" y="363">- Line 1 / 第 1 行: model, active, cost</text>
<text class="mono-small" x="660" y="394">- Line 2 / 第 2 行: cwd, git, context</text>
<text class="mono-small" x="660" y="425">- Theme / 主题: ocean | Icon style / 图标: developer</text>
<text class="mono-small" x="660" y="456">- Activation / 启用: generate only</text>
<rect class="terminal" x="636" y="526" width="874" height="228" rx="24"/>
<rect x="636" y="526" width="874" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="660" cy="548" r="6" fill="#fb7185"/>
<circle cx="682" cy="548" r="6" fill="#fbbf24"/>
<circle cx="704" cy="548" r="6" fill="#34d399"/>
<text class="small" x="732" y="553">Generated custom statusline / 生成后的 custom 脚本</text>
<rect x="636" y="570" width="874" height="6" fill="#10b981"/>
<text class="mono-small" x="660" y="614">λ Claude Opus 4.6 │ ● Active │ $ $0.28</text>
<text class="mono-small" x="660" y="645">:: cl/cc-statusline │ git main ✓ │ [] 92.5K/200.0K █████░░░░ 46%</text>
<text class="mono-small" x="660" y="676"></text>
<text class="mono-small" x="660" y="707">Output file / 输出文件: ~/.claude/statusline.custom.sh</text>
<text class="mono-small" x="660" y="738">settings.json change / 设置改动: none (generate only)</text>
<text class="accent-text" x="636" y="792">The skill previews first, then decides whether to activate or only generate / 先预览,再决定是立即启用还是仅生成。</text>
</svg>
FILE:assets/screenshots/installed-statusline-examples.svg
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-labelledby="title desc">
<title>Installed statusline examples / 安装后状态栏示例</title>
<desc>Representative runtime layouts for Full, Developer, and Minimal presets.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0b1020" />
<stop offset="55%" stop-color="#10192b" />
<stop offset="100%" stop-color="#1e293b" />
</linearGradient>
</defs>
<style>
.bg { fill: url(#bg); }
.panel { fill: #111827; stroke: #243041; stroke-width: 1.2; }
.panel-soft { fill: #0f172a; stroke: #243041; stroke-width: 1.2; }
.panel-muted { fill: #0b1220; stroke: #1f2937; stroke-width: 1.2; }
.terminal { fill: #0b1020; stroke: #334155; stroke-width: 1.2; }
.title { fill: #f8fafc; font: 700 34px 'Segoe UI', 'Inter', Arial, sans-serif; }
.subtitle { fill: #94a3b8; font: 500 17px 'Segoe UI', 'Inter', Arial, sans-serif; }
.section { fill: #e2e8f0; font: 700 21px 'Segoe UI', 'Inter', Arial, sans-serif; }
.body { fill: #dbe4f0; font: 500 18px 'Segoe UI', 'Inter', Arial, sans-serif; }
.small { fill: #94a3b8; font: 500 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.mono { fill: #e5edf7; font: 600 19px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-small { fill: #dbe4f0; font: 500 17px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-tiny { fill: #cbd5e1; font: 500 15px 'Cascadia Code', Consolas, Menlo, monospace; }
.chip { fill: #0f172a; stroke: #334155; stroke-width: 1; }
.chip-text { fill: #cbd5e1; font: 600 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.badge { fill: #1d4ed8; }
.badge-text { fill: #eff6ff; font: 700 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.accent-text { fill: #7dd3fc; font: 700 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.green { fill: #86efac; }
.yellow { fill: #fde68a; }
.orange { fill: #fdba74; }
.pink { fill: #f9a8d4; }
.blue { fill: #93c5fd; }
.muted { fill: #64748b; }
</style>
<rect class="bg" x="0" y="0" width="1600" height="900" rx="0"/>
<rect x="48" y="38" width="1504" height="824" rx="28" fill="rgba(15,23,42,0.65)" stroke="#334155" stroke-width="1.2"/>
<text class="title" x="90" y="102">Installed statusline examples / 安装后状态栏示例</text>
<text class="subtitle" x="90" y="136">Representative runtime layouts for Full, Developer, and Minimal presets.</text>
<rect class="terminal" x="90" y="186" width="1420" height="178" rx="24"/>
<rect x="90" y="186" width="1420" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="114" cy="208" r="6" fill="#fb7185"/>
<circle cx="136" cy="208" r="6" fill="#fbbf24"/>
<circle cx="158" cy="208" r="6" fill="#34d399"/>
<text class="small" x="186" y="213">Full / 完整版 · aurora · classic</text>
<rect x="90" y="230" width="1420" height="6" fill="#8b5cf6"/>
<text class="mono-small" x="114" y="274">✨ Claude Opus 4.6 │ ⚡ High · 🧠 Think · 🚀 Normal · 🔐 Plan │ ⚙ v2.1.77 │ ● Active</text>
<text class="mono-small" x="114" y="305">🔋 92.5K/200.0K █████░░░░ 46% │ 🛠 Skills:4 · 🔌 MCP:1 │ 📂 cl/cc-statusline │ 🌿 main ✓</text>
<text class="mono-small" x="114" y="336">💬 Ctx ↑92.5K ↓4.8K │ 📈 Sum ↑128.0K ↓12.4K (140.4K) │ ⏱ API 14s · ⏳ TTL 19s │ 💰 $0.28</text>
<rect class="terminal" x="90" y="402" width="1420" height="178" rx="24"/>
<rect x="90" y="402" width="1420" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="114" cy="424" r="6" fill="#fb7185"/>
<circle cx="136" cy="424" r="6" fill="#fbbf24"/>
<circle cx="158" cy="424" r="6" fill="#34d399"/>
<text class="small" x="186" y="429">Developer / 开发者版 · ocean · developer</text>
<rect x="90" y="446" width="1420" height="6" fill="#22d3ee"/>
<text class="mono-small" x="114" y="490">λ Claude Opus 4.6 │ ≡ High · ∴ Think · - Default │ ● Active</text>
<text class="mono-small" x="114" y="521">:: cl/cc-statusline │ git feat/statusline (+3 ?1) │ [] 92.5K/200.0K █████░░░░ 46%</text>
<text class="mono-small" x="114" y="552">in Ctx ↑92.5K ↓4.8K │ Σ Sum ↑128.0K ↓12.4K (140.4K) │ api 14s · all 19s │ $ $0.28</text>
<rect class="terminal" x="90" y="618" width="1420" height="132" rx="24"/>
<rect x="90" y="618" width="1420" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="114" cy="640" r="6" fill="#fb7185"/>
<circle cx="136" cy="640" r="6" fill="#fbbf24"/>
<circle cx="158" cy="640" r="6" fill="#34d399"/>
<text class="small" x="186" y="645">Minimal / 极简版 · mono · minimal</text>
<rect x="90" y="662" width="1420" height="6" fill="#94a3b8"/>
<text class="mono-small" x="114" y="706">M Claude Opus 4.6 │ V v2.1.77 │ • Active │ $ $0.28</text>
<text class="accent-text" x="90" y="798">These examples match the current preset metadata and runtime layout / 这些示例对应当前预设元数据与运行时布局。</text>
</svg>
FILE:assets/screenshots/preset-selection.svg
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-labelledby="title desc">
<title>Preset selection / 预设选择</title>
<desc>Four bilingual presets included in cc-statusline 0.1.0.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0b1020" />
<stop offset="55%" stop-color="#10192b" />
<stop offset="100%" stop-color="#1e293b" />
</linearGradient>
</defs>
<style>
.bg { fill: url(#bg); }
.panel { fill: #111827; stroke: #243041; stroke-width: 1.2; }
.panel-soft { fill: #0f172a; stroke: #243041; stroke-width: 1.2; }
.panel-muted { fill: #0b1220; stroke: #1f2937; stroke-width: 1.2; }
.terminal { fill: #0b1020; stroke: #334155; stroke-width: 1.2; }
.title { fill: #f8fafc; font: 700 34px 'Segoe UI', 'Inter', Arial, sans-serif; }
.subtitle { fill: #94a3b8; font: 500 17px 'Segoe UI', 'Inter', Arial, sans-serif; }
.section { fill: #e2e8f0; font: 700 21px 'Segoe UI', 'Inter', Arial, sans-serif; }
.body { fill: #dbe4f0; font: 500 18px 'Segoe UI', 'Inter', Arial, sans-serif; }
.small { fill: #94a3b8; font: 500 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.mono { fill: #e5edf7; font: 600 19px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-small { fill: #dbe4f0; font: 500 17px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-tiny { fill: #cbd5e1; font: 500 15px 'Cascadia Code', Consolas, Menlo, monospace; }
.chip { fill: #0f172a; stroke: #334155; stroke-width: 1; }
.chip-text { fill: #cbd5e1; font: 600 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.badge { fill: #1d4ed8; }
.badge-text { fill: #eff6ff; font: 700 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.accent-text { fill: #7dd3fc; font: 700 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.green { fill: #86efac; }
.yellow { fill: #fde68a; }
.orange { fill: #fdba74; }
.pink { fill: #f9a8d4; }
.blue { fill: #93c5fd; }
.muted { fill: #64748b; }
</style>
<rect class="bg" x="0" y="0" width="1600" height="900" rx="0"/>
<rect x="48" y="38" width="1504" height="824" rx="28" fill="rgba(15,23,42,0.65)" stroke="#334155" stroke-width="1.2"/>
<text class="title" x="90" y="102">Preset selection / 预设选择</text>
<text class="subtitle" x="90" y="136">Four bilingual presets included in cc-statusline 0.1.0.</text>
<rect class="panel" x="90" y="182" width="680" height="260" rx="24"/>
<rect x="90" y="182" width="680" height="10" rx="24" fill="#8b5cf6"/>
<text class="section" x="116" y="230">Full / 完整版</text>
<text class="small" x="116" y="259">Three-line default preset · 3 行默认预设</text>
<rect class="badge" x="662" y="206" width="78" height="30" rx="15"/>
<text class="badge-text" x="701" y="226" text-anchor="middle">3 lines</text>
<text class="body" x="116" y="300">Line 1: model · modes · version · active</text>
<text class="body" x="116" y="334">Line 2: context · tools · cwd · git</text>
<text class="body" x="116" y="368">Line 3: ctx_tokens · sum_tokens · duration · cost</text>
<text class="body" x="116" y="402">Closest to the current Miluer layout / 最接近当前 Miluer 风格</text>
<rect class="panel" x="830" y="182" width="680" height="260" rx="24"/>
<rect x="830" y="182" width="680" height="10" rx="24" fill="#38bdf8"/>
<text class="section" x="856" y="230">Standard / 标准版</text>
<text class="small" x="856" y="259">Balanced daily preset · 适合日常使用</text>
<rect class="badge" x="1402" y="206" width="78" height="30" rx="15"/>
<text class="badge-text" x="1441" y="226" text-anchor="middle">2 lines</text>
<text class="body" x="856" y="300">Line 1: model · modes · version · active</text>
<text class="body" x="856" y="334">Line 2: context · tools · cwd · git</text>
<text class="body" x="856" y="368">Line 3: (empty)</text>
<text class="body" x="856" y="402">Less noise, same essentials / 更均衡、更易读</text>
<rect class="panel" x="90" y="478" width="680" height="260" rx="24"/>
<rect x="90" y="478" width="680" height="10" rx="24" fill="#94a3b8"/>
<text class="section" x="116" y="526">Minimal / 极简版</text>
<text class="small" x="116" y="555">Single-line essentials only · 单行只保留关键项</text>
<rect class="badge" x="662" y="502" width="78" height="30" rx="15"/>
<text class="badge-text" x="701" y="522" text-anchor="middle">1 line</text>
<text class="body" x="116" y="596">Line 1: model · version · active · cost</text>
<text class="body" x="116" y="630">Line 2: (empty)</text>
<text class="body" x="116" y="664">Line 3: (empty)</text>
<text class="body" x="116" y="698">Best when you want the lowest visual noise / 视觉干扰最低</text>
<rect class="panel" x="830" y="478" width="680" height="260" rx="24"/>
<rect x="830" y="478" width="680" height="10" rx="24" fill="#10b981"/>
<text class="section" x="856" y="526">Developer / 开发者版</text>
<text class="small" x="856" y="555">Git + token focused preset · 强调 Git 与 Token</text>
<rect class="badge" x="1402" y="502" width="78" height="30" rx="15"/>
<text class="badge-text" x="1441" y="522" text-anchor="middle">3 lines</text>
<text class="body" x="856" y="596">Line 1: model · modes · active</text>
<text class="body" x="856" y="630">Line 2: cwd · git · context</text>
<text class="body" x="856" y="664">Line 3: ctx_tokens · sum_tokens · duration · cost</text>
<text class="body" x="856" y="698">Optimized for active coding sessions / 面向高频开发会话</text>
<text class="accent-text" x="90" y="792">Preset names, labels, and descriptions stay bilingual in the skill UI / 预设名、描述与关键提示都会保持双语。</text>
</svg>
FILE:assets/screenshots/theme-and-icons.svg
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-labelledby="title desc">
<title>Themes + icon styles / 主题与图标风格</title>
<desc>Current theme palette and icon style combinations used by cc-statusline.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0b1020" />
<stop offset="55%" stop-color="#10192b" />
<stop offset="100%" stop-color="#1e293b" />
</linearGradient>
</defs>
<style>
.bg { fill: url(#bg); }
.panel { fill: #111827; stroke: #243041; stroke-width: 1.2; }
.panel-soft { fill: #0f172a; stroke: #243041; stroke-width: 1.2; }
.panel-muted { fill: #0b1220; stroke: #1f2937; stroke-width: 1.2; }
.terminal { fill: #0b1020; stroke: #334155; stroke-width: 1.2; }
.title { fill: #f8fafc; font: 700 34px 'Segoe UI', 'Inter', Arial, sans-serif; }
.subtitle { fill: #94a3b8; font: 500 17px 'Segoe UI', 'Inter', Arial, sans-serif; }
.section { fill: #e2e8f0; font: 700 21px 'Segoe UI', 'Inter', Arial, sans-serif; }
.body { fill: #dbe4f0; font: 500 18px 'Segoe UI', 'Inter', Arial, sans-serif; }
.small { fill: #94a3b8; font: 500 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.mono { fill: #e5edf7; font: 600 19px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-small { fill: #dbe4f0; font: 500 17px 'Cascadia Code', Consolas, Menlo, monospace; }
.mono-tiny { fill: #cbd5e1; font: 500 15px 'Cascadia Code', Consolas, Menlo, monospace; }
.chip { fill: #0f172a; stroke: #334155; stroke-width: 1; }
.chip-text { fill: #cbd5e1; font: 600 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.badge { fill: #1d4ed8; }
.badge-text { fill: #eff6ff; font: 700 14px 'Segoe UI', 'Inter', Arial, sans-serif; }
.accent-text { fill: #7dd3fc; font: 700 15px 'Segoe UI', 'Inter', Arial, sans-serif; }
.green { fill: #86efac; }
.yellow { fill: #fde68a; }
.orange { fill: #fdba74; }
.pink { fill: #f9a8d4; }
.blue { fill: #93c5fd; }
.muted { fill: #64748b; }
</style>
<rect class="bg" x="0" y="0" width="1600" height="900" rx="0"/>
<rect x="48" y="38" width="1504" height="824" rx="28" fill="rgba(15,23,42,0.65)" stroke="#334155" stroke-width="1.2"/>
<text class="title" x="90" y="102">Themes + icon styles / 主题与图标风格</text>
<text class="subtitle" x="90" y="136">Current theme palette and icon style combinations used by cc-statusline.</text>
<rect class="panel" x="90" y="184" width="340" height="236" rx="24"/>
<rect x="90" y="184" width="340" height="10" rx="24" fill="#8b5cf6"/>
<text class="section" x="116" y="232">Aurora / 极光</text>
<text class="small" x="116" y="261">Blue-purple default Miluer look</text>
<text class="body" x="116" y="302">Base palette: violet · cyan · neon green</text>
<text class="body" x="116" y="336">Recommended preset: Full / 完整版</text>
<text class="body" x="116" y="370">Good for the default showcase / 默认展示首选</text>
<rect class="panel" x="450" y="184" width="340" height="236" rx="24"/>
<rect x="450" y="184" width="340" height="10" rx="24" fill="#fb923c"/>
<text class="section" x="476" y="232">Sunset / 日落</text>
<text class="small" x="476" y="261">Warm orange-yellow-red palette</text>
<text class="body" x="476" y="302">Base palette: amber · orange · coral</text>
<text class="body" x="476" y="336">Recommended preset: Standard / 标准版</text>
<text class="body" x="476" y="370">More lively and warm / 更有活力</text>
<rect class="panel" x="810" y="184" width="340" height="236" rx="24"/>
<rect x="810" y="184" width="340" height="10" rx="24" fill="#22d3ee"/>
<text class="section" x="836" y="232">Ocean / 海洋</text>
<text class="small" x="836" y="261">Cool cyan-blue-green palette</text>
<text class="body" x="836" y="302">Base palette: cyan · teal · blue</text>
<text class="body" x="836" y="336">Recommended preset: Developer / 开发者版</text>
<text class="body" x="836" y="370">Calm technical tone / 冷静技术感</text>
<rect class="panel" x="1170" y="184" width="340" height="236" rx="24"/>
<rect x="1170" y="184" width="340" height="10" rx="24" fill="#94a3b8"/>
<text class="section" x="1196" y="232">Mono / 单色</text>
<text class="small" x="1196" y="261">Low-noise monochrome palette</text>
<text class="body" x="1196" y="302">Base palette: white · gray · charcoal</text>
<text class="body" x="1196" y="336">Recommended preset: Minimal / 极简版</text>
<text class="body" x="1196" y="370">Clean and quiet / 低干扰</text>
<rect class="terminal" x="90" y="470" width="450" height="258" rx="24"/>
<rect x="90" y="470" width="450" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="114" cy="492" r="6" fill="#fb7185"/>
<circle cx="136" cy="492" r="6" fill="#fbbf24"/>
<circle cx="158" cy="492" r="6" fill="#34d399"/>
<text class="small" x="186" y="497">classic / 经典</text>
<rect x="90" y="514" width="450" height="6" fill="#8b5cf6"/>
<text class="mono-small" x="114" y="558">✨ Claude Opus 4.6 │ ⚡ High · 🧠 Think │ ● Active</text>
<text class="mono-small" x="114" y="589">🔋 92.5K/200.0K █████░░░░ 46% │ 📂 cl/repo │ 🌿 main ✓</text>
<text class="mono-small" x="114" y="620">💬 Ctx ↑92.5K ↓4.8K │ 📈 Sum ↑128.0K ↓12.4K │ 💰 $0.28</text>
<rect class="terminal" x="575" y="470" width="450" height="258" rx="24"/>
<rect x="575" y="470" width="450" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="599" cy="492" r="6" fill="#fb7185"/>
<circle cx="621" cy="492" r="6" fill="#fbbf24"/>
<circle cx="643" cy="492" r="6" fill="#34d399"/>
<text class="small" x="671" y="497">minimal / 极简</text>
<rect x="575" y="514" width="450" height="6" fill="#94a3b8"/>
<text class="mono-small" x="599" y="558">M Claude Opus 4.6 │ E High · T Think │ • Active</text>
<text class="mono-small" x="599" y="589">C 92.5K/200.0K █████░░░░ 46% │ @ cl/repo │ git main ✓</text>
<text class="mono-small" x="599" y="620">I/O Ctx ↑92.5K ↓4.8K │ Σ Sum ↑128.0K ↓12.4K │ $ $0.28</text>
<rect class="terminal" x="1060" y="470" width="450" height="258" rx="24"/>
<rect x="1060" y="470" width="450" height="44" rx="24" fill="#111827" stroke="#334155" stroke-width="1.2"/>
<circle cx="1084" cy="492" r="6" fill="#fb7185"/>
<circle cx="1106" cy="492" r="6" fill="#fbbf24"/>
<circle cx="1128" cy="492" r="6" fill="#34d399"/>
<text class="small" x="1156" y="497">developer / 开发者</text>
<rect x="1060" y="514" width="450" height="6" fill="#10b981"/>
<text class="mono-small" x="1084" y="558">λ Claude Opus 4.6 │ ≡ High · ∴ Think │ ● Active</text>
<text class="mono-small" x="1084" y="589">[] 92.5K/200.0K █████░░░░ 46% │ :: cl/repo │ git main ✓</text>
<text class="mono-small" x="1084" y="620">in Ctx ↑92.5K ↓4.8K │ Σ Sum ↑128.0K ↓12.4K │ $ $0.28</text>
<text class="accent-text" x="90" y="786">Themes and icon styles can be switched independently / 主题与图标风格可以独立切换。</text>
</svg>
FILE:icons/classic.json
{
"id": "classic",
"label_en": "Classic",
"label_zh": "经典",
"description_en": "Emoji-rich visual style close to the current statusline look.",
"description_zh": "更接近当前状态栏风格的高识别度 emoji 方案。"
}
FILE:icons/developer.json
{
"id": "developer",
"label_en": "Developer",
"label_zh": "开发者",
"description_en": "Sharper technical icon style intended for git, tokens, and diagnostics.",
"description_zh": "更偏技术感,适合 Git、Token 和诊断信息场景。"
}
FILE:icons/minimal.json
{
"id": "minimal",
"label_en": "Minimal",
"label_zh": "极简",
"description_en": "Lower-noise icon style with fewer emojis and simpler separators.",
"description_zh": "减少 emoji 和装饰,整体更克制。"
}
FILE:presets/developer.json
{
"id": "developer",
"label_en": "Developer",
"label_zh": "开发者版",
"description_en": "Three-line preset that emphasizes git state, context pressure, and token visibility.",
"description_zh": "三行开发者预设,重点强化 Git 状态、上下文压力和 Token 可见性。",
"lines": 3,
"modules": {
"1": ["model", "modes", "active"],
"2": ["cwd", "git", "context"],
"3": ["ctx_tokens", "sum_tokens", "duration", "cost"]
},
"is_default": false
}
FILE:presets/full.json
{
"id": "full",
"label_en": "Full",
"label_zh": "完整版",
"description_en": "Three-line preset with the complete Miluer-style statusline layout.",
"description_zh": "三行完整布局,尽量贴近当前 Miluer 风格的状态栏信息密度。",
"lines": 3,
"modules": {
"1": ["model", "modes", "version", "active"],
"2": ["context", "tools", "cwd", "git"],
"3": ["ctx_tokens", "sum_tokens", "duration", "cost"]
},
"is_default": true
}
FILE:presets/minimal.json
{
"id": "minimal",
"label_en": "Minimal",
"label_zh": "极简版",
"description_en": "Single-line preset that keeps only the essentials visible.",
"description_zh": "单行极简预设,只保留最关键的信息。",
"lines": 1,
"modules": {
"1": ["model", "version", "active", "cost"],
"2": [],
"3": []
},
"is_default": false
}
FILE:presets/standard.json
{
"id": "standard",
"label_en": "Standard",
"label_zh": "标准版",
"description_en": "Balanced two-line preset for everyday Claude Code usage.",
"description_zh": "适合日常 Claude Code 使用的双行均衡预设。",
"lines": 2,
"modules": {
"1": ["model", "modes", "version", "active"],
"2": ["context", "tools", "cwd", "git"],
"3": []
},
"is_default": false
}
FILE:references/modules.md
# Modules / 模块说明
## Base group / 基础信息
- `model` — model name / 模型名称
- `modes` — effort, think, fast, permission mode / Effort、Think、Fast、权限模式
- `version` — Claude Code version / Claude Code 版本
- `active` — active session marker / 活跃会话标记
## Environment group / 环境信息
- `context` — context bar and usage pressure / 上下文占用与进度条
- `tools` — skills and MCP counts / Skills 与 MCP 数量
- `cwd` — current directory / 当前目录
- `git` — branch and change status / 分支与改动状态
## Metrics group / 统计信息
- `ctx_tokens` — current context input/output tokens / 当前上下文输入输出 Token
- `sum_tokens` — cumulative session token totals / 会话累计 Token
- `duration` — API and total duration / API 耗时与总耗时
- `cost` — visible session cost when non-zero / 非 0 时显示费用
## Custom extensions / 自定义扩展
- Additional modules can be proposed by the user and mapped into the generated script if they are safe and clearly defined.
- 用户可以提出额外模块,只要语义明确且实现安全,就可以映射进生成脚本。
FILE:references/trigger-phrases.md
# Trigger phrases / 触发词清单
## Trigger rule / 触发规则
Use this skill when the request is about **Claude Code** statusline / status bar behavior.
当请求明确在说 **Claude Code** 的状态栏时,使用这个 skill。
Trigger even for casual phrasing if the intent is clearly one of these:
即使表达很口语化,只要意图明显属于以下类型,也应触发:
- install or configure / 安装或配置
- choose or switch presets / 选择或切换预设
- generate custom layouts / 生成自定义布局
- switch themes or icon styles / 切换主题或图标风格
- beautify or optimize / 美化或优化
- uninstall or restore default / 卸载或恢复默认
- troubleshoot broken setup / 排查失效配置
Do not trigger when the user is really asking about shell prompts, Windows taskbar styling, VS Code status bars, or generic web app UI bars unless they clearly tie it back to Claude Code.
如果用户真正想说的是 shell prompt、Windows 任务栏、VS Code 状态栏或网页 UI 状态栏,而不是 Claude Code,就不要误触发。
## Install / 配置 / 安装
### English
- install Claude Code statusline
- setup a status bar for Claude Code
- configure my Claude Code statusline
- add a statusline to Claude Code
- give me a preset statusline for Claude Code
- help me set up Claude Code status bar on Windows
### 中文
- 安装 Claude Code 状态栏
- 配置状态栏
- 帮我设置 Claude Code 状态栏
- 给 Claude Code 加个状态栏
- 给我一键配置状态栏
- 帮我装一个预设状态栏
## Preset switch / 预设切换
### English
- switch to the developer preset
- change my statusline preset to minimal
- use a cleaner preset for Claude Code
- switch back to the full preset
### 中文
- 把状态栏切到开发者版
- 换成极简版状态栏
- 切回完整版预设
- 给我换一个更清爽的预设
## Customize / 自定义 / 生成
### English
- create a custom Claude Code statusline
- build a one-line statusline for Claude Code
- generate a custom layout from the full preset
- customize my statusline with git and token info
- switch the statusline theme
- change the icon style for Claude Code statusline
### 中文
- 生成自定义状态栏
- 自定义 Claude Code 状态栏
- 帮我做一个 2 行状态栏
- 从完整版改一个自定义布局
- 只保留 Git、Token、Context
- 调整状态栏主题
- 切换状态栏图标风格
## Beautify / Optimize / 美化 / 优化
### English
- beautify Claude Code statusline
- optimize statusline layout
- improve statusline readability
- make the statusline cleaner
- simplify my Claude Code status bar
### 中文
- 美化 Claude Code 状态栏
- 优化状态栏布局
- 让状态栏更清晰
- 调整状态栏样式
- 把状态栏做得更干净一点
## Uninstall / Restore / 卸载 / 恢复默认
### English
- uninstall statusline
- disable statusline
- restore default statusline
- remove statusline setup
- go back to the default Claude Code status bar
### 中文
- 卸载状态栏
- 禁用状态栏
- 恢复默认状态栏
- 移除状态栏配置
- 切回默认的 Claude Code 状态栏
## Troubleshoot / 排障 / 修复
### English
- fix my Claude Code statusline install
- the statusLine command is broken
- my statusline stopped working
- troubleshoot Claude Code status bar setup
- help me repair the statusline config
### 中文
- 帮我修状态栏安装
- 状态栏装完没生效
- statusLine 配置坏了
- 帮我排查 Claude Code 状态栏问题
- 修一下状态栏命令
## Near misses / 临界不触发场景
These are intentionally similar, but should **not** trigger this skill unless the user later clarifies they mean Claude Code.
这些表达看起来接近,但除非用户后续明确说的是 Claude Code,否则**不应**触发本 skill。
### English
- make my zsh prompt cleaner
- customize the VS Code status bar
- change my Windows taskbar style
- build a web app status bar component
- theme my terminal prompt with git info
### 中文
- 美化我的 zsh 提示符
- 改 VS Code 状态栏颜色
- 调整 Windows 任务栏样式
- 做一个网页顶部状态栏组件
- 给终端 prompt 加 Git 信息
FILE:scripts/activate_custom_statusline.sh
#!/usr/bin/env bash
set -euo pipefail
CLAUDE_DIR="-$HOME/.claude"
SETTINGS_FILE="-$CLAUDE_DIR/settings.json"
STATE_FILE="-$CLAUDE_DIR/cc-statusline-state.json"
TARGET_PATH="-$CLAUDE_DIR/statusline.custom.sh"
PRESET_LABEL="custom"
THEME_LABEL="-custom"
ICON_STYLE_LABEL="-custom"
STATUSLINE_COMMAND="bash \"$TARGET_PATH\""
JQ_BIN=""
log() {
printf '[cc-statusline][activate-custom] %s\n' "$1"
}
warn() {
printf '[cc-statusline][activate-custom][warn] %s\n' "$1"
}
fail_manual() {
printf '[cc-statusline][activate-custom][error] %s\n' "$1" >&2
printf 'Manual fallback:\n' >&2
printf '1. Confirm the custom script exists at %s\n' "$TARGET_PATH" >&2
printf '2. Update only the statusLine field in %s\n' "$SETTINGS_FILE" >&2
printf '3. Use this command value: %s\n' "$STATUSLINE_COMMAND" >&2
exit 1
}
choose_jq_bin() {
if [ -x "$HOME/.claude/jq.exe" ] && "$HOME/.claude/jq.exe" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq.exe"
return 0
fi
if [ -x "$HOME/.claude/jq" ] && "$HOME/.claude/jq" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq"
return 0
fi
if command -v jq >/dev/null 2>&1; then
command -v jq
return 0
fi
return 1
}
choose_python() {
if command -v python3 >/dev/null 2>&1; then
command -v python3
return 0
fi
if command -v python >/dev/null 2>&1; then
command -v python
return 0
fi
return 1
}
ensure_inputs() {
[ -f "$TARGET_PATH" ] || fail_manual "Custom statusline script not found: $TARGET_PATH"
mkdir -p "$CLAUDE_DIR"
}
settings_valid_json() {
[ ! -f "$SETTINGS_FILE" ] && return 0
"$JQ_BIN" -e . "$SETTINGS_FILE" >/dev/null 2>&1
}
save_previous_statusline_state() {
local previous_json timestamp
previous_json='null'
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date)
if [ -f "$SETTINGS_FILE" ] && settings_valid_json; then
previous_json=$("$JQ_BIN" -c '.statusLine // null' "$SETTINGS_FILE" 2>/dev/null || printf 'null')
fi
"$JQ_BIN" -n \
--arg savedAt "$timestamp" \
--arg platform "activation" \
--arg preset "$PRESET_LABEL" \
--arg theme "$THEME_LABEL" \
--arg iconStyle "$ICON_STYLE_LABEL" \
--arg targetPath "$TARGET_PATH" \
--arg backupPath "" \
--arg command "$STATUSLINE_COMMAND" \
--arg sourceScript "$TARGET_PATH" \
--argjson previousStatusLine "$previous_json" \
'{
tool: "cc-statusline",
savedAt: $savedAt,
platform: $platform,
preset: $preset,
theme: $theme,
iconStyle: $iconStyle,
targetPath: $targetPath,
backupPath: $backupPath,
command: $command,
sourceScript: $sourceScript,
previousStatusLine: $previousStatusLine
}' > "$STATE_FILE"
}
update_settings_with_jq() {
local tmp_file
tmp_file="$SETTINGS_FILE.tmp.$$"
if [ ! -f "$SETTINGS_FILE" ]; then
"$JQ_BIN" -n --arg cmd "$STATUSLINE_COMMAND" '{statusLine:{type:"command",command:$cmd,padding:0}}' > "$SETTINGS_FILE"
return 0
fi
settings_valid_json || return 1
"$JQ_BIN" --arg cmd "$STATUSLINE_COMMAND" '.statusLine = {type:"command", command:$cmd, padding:0}' "$SETTINGS_FILE" > "$tmp_file"
mv "$tmp_file" "$SETTINGS_FILE"
}
update_settings_with_python() {
local py
py=$(choose_python) || return 1
"$py" - "$SETTINGS_FILE" "$STATUSLINE_COMMAND" <<'PY'
import json
import os
import sys
settings_file = sys.argv[1]
command = sys.argv[2]
data = {}
if os.path.exists(settings_file):
with open(settings_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data['statusLine'] = {
'type': 'command',
'command': command,
'padding': 0,
}
with open(settings_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
}
update_settings() {
if update_settings_with_jq; then
return 0
fi
warn 'jq-based activation failed. Attempting Python fallback.'
if update_settings_with_python; then
return 0
fi
fail_manual 'Failed to activate custom statusline automatically.'
}
main() {
ensure_inputs
JQ_BIN=$(choose_jq_bin) || fail_manual 'jq is required to update settings.json.'
save_previous_statusline_state
update_settings
log "Activated custom statusline: $TARGET_PATH"
log "Saved previous statusLine snapshot to $STATE_FILE"
}
main "$@"
FILE:scripts/activate_preset_statusline.sh
#!/usr/bin/env bash
set -euo pipefail
PRESET="-full"
THEME="-aurora"
ICON_STYLE="-classic"
TARGET_PATH="-${CC_STATUSLINE_CLAUDE_DIR:-$HOME/.claude/statusline.sh}"
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
case "$(uname -s 2>/dev/null)" in
Darwin*) INSTALLER="$SCRIPT_DIR/install_statusline_macos.sh" ;;
CYGWIN*|MINGW*|MSYS*) INSTALLER="$SCRIPT_DIR/install_statusline_windows.sh" ;;
*) INSTALLER="$SCRIPT_DIR/install_statusline_linux.sh" ;;
esac
exec bash "$INSTALLER" "$PRESET" "$THEME" "$ICON_STYLE" "$TARGET_PATH"
FILE:scripts/generate_custom_statusline.sh
#!/usr/bin/env bash
set -euo pipefail
TARGET_PATH="-$HOME/.claude/statusline.custom.sh"
SCRIPT_ARGC=$#
SCRIPT_ARGS=("$@")
value_or_default() {
local index=$1
local default_value=$2
local array_index=$((index - 1))
if [ "$SCRIPT_ARGC" -ge "$index" ]; then
printf '%s' "SCRIPT_ARGS[$array_index]"
else
printf '%s' "$default_value"
fi
}
normalize_line() {
case "$1" in
-|none|empty|null)
printf ''
;;
*)
printf '%s' "$1"
;;
esac
}
preview_line() {
if [ -n "$1" ]; then
printf '%s' "$1"
else
printf '(empty)'
fi
}
LINE_1=$(normalize_line "$(value_or_default 2 "model,modes,version,active")")
LINE_2=$(normalize_line "$(value_or_default 3 "context,tools,cwd,git")")
LINE_3=$(normalize_line "$(value_or_default 4 "ctx_tokens,sum_tokens,duration,cost")")
THEME=$(value_or_default 5 "aurora")
ICON_STYLE=$(value_or_default 6 "classic")
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
RUNTIME_SCRIPT="$SCRIPT_DIR/statusline.sh"
TARGET_DIR="$(dirname "$TARGET_PATH")"
mkdir -p "$TARGET_DIR"
cp "$RUNTIME_SCRIPT" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
cat <<EOF >> "$TARGET_PATH"
# ---- cc-statusline custom layout override ----
export CC_STATUSLINE_CUSTOM_LAYOUT_MODE=true
export CC_STATUSLINE_CUSTOM_THEME="THEME"
export CC_STATUSLINE_CUSTOM_ICON_STYLE="ICON_STYLE"
export CC_STATUSLINE_CUSTOM_LINE_1="LINE_1"
export CC_STATUSLINE_CUSTOM_LINE_2="LINE_2"
export CC_STATUSLINE_CUSTOM_LINE_3="LINE_3"
EOF
printf 'Generated custom statusline at %s\n' "$TARGET_PATH"
printf 'Line 1: %s\n' "$(preview_line "$LINE_1")"
printf 'Line 2: %s\n' "$(preview_line "$LINE_2")"
printf 'Line 3: %s\n' "$(preview_line "$LINE_3")"
printf 'Theme: %s\n' "$THEME"
printf 'Icon style: %s\n' "$ICON_STYLE"
FILE:scripts/install_jq.sh
#!/bin/bash
# install_jq.sh — Auto-detect and install jq on Windows/macOS/Linux
set -e
JQ_CLAUDE_PATH="$HOME/.claude/jq"
JQ_CLAUDE_EXE="$HOME/.claude/jq.exe"
detect_os() {
case "$(uname -s 2>/dev/null)" in
Linux*) echo "linux" ;;
Darwin*) echo "macos" ;;
CYGWIN*|MINGW*|MSYS*) echo "windows" ;;
*)
# fallback: check WINDIR
[ -n "$WINDIR" ] && echo "windows" || echo "linux"
;;
esac
}
check_jq() {
# Check ~/.claude/jq.exe (Windows convention used by statusline)
if [ -f "$JQ_CLAUDE_EXE" ] && "$JQ_CLAUDE_EXE" --version &>/dev/null; then
echo "$JQ_CLAUDE_EXE"
return 0
fi
# Check ~/.claude/jq
if [ -f "$JQ_CLAUDE_PATH" ] && "$JQ_CLAUDE_PATH" --version &>/dev/null; then
echo "$JQ_CLAUDE_PATH"
return 0
fi
# Check system jq
if command -v jq &>/dev/null; then
echo "$(command -v jq)"
return 0
fi
return 1
}
install_jq_windows() {
echo "Downloading jq for Windows..."
local url="https://github.com/jqlang/jq/releases/latest/download/jq-windows-amd64.exe"
local dest="$JQ_CLAUDE_EXE"
mkdir -p "$HOME/.claude"
if command -v curl &>/dev/null; then
curl -fsSL -o "$dest" "$url"
elif command -v wget &>/dev/null; then
wget -q -O "$dest" "$url"
elif command -v powershell.exe &>/dev/null; then
powershell.exe -Command "Invoke-WebRequest -Uri '$url' -OutFile '$dest'"
else
echo "ERROR: No download tool found (curl/wget/powershell). Please download jq manually:"
echo " $url"
echo " Save to: $dest"
exit 1
fi
chmod +x "$dest"
echo "jq installed at: $dest"
}
install_jq_macos() {
if command -v brew &>/dev/null; then
echo "Installing jq via Homebrew..."
brew install jq
else
echo "Downloading jq for macOS..."
local arch
arch=$(uname -m)
local url
if [ "$arch" = "arm64" ]; then
url="https://github.com/jqlang/jq/releases/latest/download/jq-macos-arm64"
else
url="https://github.com/jqlang/jq/releases/latest/download/jq-macos-amd64"
fi
mkdir -p "$HOME/.claude"
curl -fsSL -o "$JQ_CLAUDE_PATH" "$url"
chmod +x "$JQ_CLAUDE_PATH"
echo "jq installed at: $JQ_CLAUDE_PATH"
fi
}
install_jq_linux() {
# Try package managers in order
if command -v apt-get &>/dev/null; then
echo "Installing jq via apt..."
sudo apt-get install -y jq
elif command -v dnf &>/dev/null; then
echo "Installing jq via dnf..."
sudo dnf install -y jq
elif command -v yum &>/dev/null; then
echo "Installing jq via yum..."
sudo yum install -y jq
elif command -v pacman &>/dev/null; then
echo "Installing jq via pacman..."
sudo pacman -Sy --noconfirm jq
elif command -v zypper &>/dev/null; then
echo "Installing jq via zypper..."
sudo zypper install -y jq
elif command -v apk &>/dev/null; then
echo "Installing jq via apk..."
sudo apk add jq
else
# Fallback: download binary
echo "No package manager found. Downloading jq binary..."
local arch
arch=$(uname -m)
local url
case "$arch" in
x86_64) url="https://github.com/jqlang/jq/releases/latest/download/jq-linux-amd64" ;;
aarch64|arm64) url="https://github.com/jqlang/jq/releases/latest/download/jq-linux-arm64" ;;
*) echo "ERROR: Unsupported architecture: $arch. Install jq manually."; exit 1 ;;
esac
mkdir -p "$HOME/.claude"
if command -v curl &>/dev/null; then
curl -fsSL -o "$JQ_CLAUDE_PATH" "$url"
else
wget -q -O "$JQ_CLAUDE_PATH" "$url"
fi
chmod +x "$JQ_CLAUDE_PATH"
echo "jq installed at: $JQ_CLAUDE_PATH"
fi
}
main() {
echo "=== jq Detection ==="
local existing
if existing=$(check_jq); then
echo "jq already available at: $existing"
echo "Version: $($existing --version)"
exit 0
fi
echo "jq not found. Installing..."
local os
os=$(detect_os)
echo "Detected OS: $os"
case "$os" in
windows) install_jq_windows ;;
macos) install_jq_macos ;;
linux) install_jq_linux ;;
esac
# Verify
if existing=$(check_jq); then
echo "jq successfully installed: $($existing --version)"
else
echo "ERROR: jq installation failed. Please install manually from https://jqlang.github.io/jq/download/"
exit 1
fi
}
main "$@"
FILE:scripts/install_statusline_linux.sh
#!/usr/bin/env bash
set -euo pipefail
PLATFORM_NAME="Linux"
EXPECTED_OS="linux"
PRESET="-full"
THEME="-aurora"
ICON_STYLE="-classic"
TARGET_PATH="-$HOME/.claude/statusline.sh"
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
SOURCE_SCRIPT="$SCRIPT_DIR/statusline.sh"
INSTALL_JQ_SCRIPT="$SCRIPT_DIR/install_jq.sh"
CLAUDE_DIR="-$HOME/.claude"
SETTINGS_FILE="-$CLAUDE_DIR/settings.json"
STATE_FILE="-$CLAUDE_DIR/cc-statusline-state.json"
TARGET_DIR="$(dirname "$TARGET_PATH")"
BACKUP_PATH="$TARGET_DIR/$(basename "$TARGET_PATH").bak"
STATUSLINE_COMMAND="bash \"$TARGET_PATH\" \"$PRESET\" \"$THEME\" \"$ICON_STYLE\""
JQ_BIN=""
usage() {
printf 'Usage: bash scripts/install_statusline_linux.sh [preset] [theme] [icon_style] [target_path]\n'
printf 'Example: bash scripts/install_statusline_linux.sh full aurora classic "$HOME/.claude/statusline.sh"\n'
}
log() {
printf '[cc-statusline][%s] %s\n' "$PLATFORM_NAME" "$1"
}
warn() {
printf '[cc-statusline][%s][warn] %s\n' "$PLATFORM_NAME" "$1"
}
fail_manual() {
printf '[cc-statusline][%s][error] %s\n' "$PLATFORM_NAME" "$1" >&2
printf 'Manual fallback:\n' >&2
printf '1. Copy %s to %s\n' "$SOURCE_SCRIPT" "$TARGET_PATH" >&2
printf '2. Ensure jq is available at ~/.claude/jq.exe, ~/.claude/jq, or in PATH\n' >&2
printf '3. Update only the statusLine field in %s\n' "$SETTINGS_FILE" >&2
printf '4. Use this command value: %s\n' "$STATUSLINE_COMMAND" >&2
exit 1
}
validate_choice() {
case "$PRESET" in
full|standard|minimal|developer) ;;
*) fail_manual "Unsupported preset: $PRESET" ;;
esac
case "$THEME" in
aurora|sunset|ocean|mono) ;;
*) fail_manual "Unsupported theme: $THEME" ;;
esac
case "$ICON_STYLE" in
classic|minimal|developer) ;;
*) fail_manual "Unsupported icon style: $ICON_STYLE" ;;
esac
}
detect_os() {
case "$(uname -s 2>/dev/null)" in
Linux*) printf 'linux' ;;
Darwin*) printf 'macos' ;;
CYGWIN*|MINGW*|MSYS*) printf 'windows' ;;
*)
if [ -n "-" ]; then
printf 'windows'
else
printf 'unknown'
fi
;;
esac
}
warn_if_unexpected_os() {
local detected
detected=$(detect_os)
if [ "$detected" != "$EXPECTED_OS" ]; then
warn "This installer targets $PLATFORM_NAME, but detected $detected. Continuing anyway."
fi
}
ensure_paths() {
[ -f "$SOURCE_SCRIPT" ] || fail_manual "Runtime script not found: $SOURCE_SCRIPT"
mkdir -p "$CLAUDE_DIR" "$TARGET_DIR"
}
choose_jq_bin() {
if [ -x "$HOME/.claude/jq.exe" ] && "$HOME/.claude/jq.exe" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq.exe"
return 0
fi
if [ -x "$HOME/.claude/jq" ] && "$HOME/.claude/jq" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq"
return 0
fi
if command -v jq >/dev/null 2>&1; then
command -v jq
return 0
fi
return 1
}
ensure_jq() {
if JQ_BIN=$(choose_jq_bin); then
log "Using jq at $JQ_BIN"
return 0
fi
warn "jq not found. Attempting automatic install."
if [ -f "$INSTALL_JQ_SCRIPT" ]; then
bash "$INSTALL_JQ_SCRIPT" || true
fi
if JQ_BIN=$(choose_jq_bin); then
log "jq installed successfully at $JQ_BIN"
return 0
fi
fail_manual 'jq is required for the statusline runtime and could not be installed automatically.'
}
choose_python() {
if command -v python3 >/dev/null 2>&1; then
command -v python3
return 0
fi
if command -v python >/dev/null 2>&1; then
command -v python
return 0
fi
return 1
}
settings_valid_json() {
[ ! -f "$SETTINGS_FILE" ] && return 0
"$JQ_BIN" -e . "$SETTINGS_FILE" >/dev/null 2>&1
}
read_current_statusline_json() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -c '.statusLine // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
read_current_statusline_command() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -r '.statusLine.command // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
is_existing_script_managed() {
[ -f "$TARGET_PATH" ] || return 1
grep -q 'cc-statusline runtime script' "$TARGET_PATH" 2>/dev/null
}
confirm_foreign_statusline() {
[ -f "$SETTINGS_FILE" ] || return 0
settings_valid_json || fail_manual "settings.json is not valid JSON and cannot be updated safely."
local current_json current_command
current_json=$(read_current_statusline_json)
[ -z "$current_json" ] && return 0
current_command=$(read_current_statusline_command)
if [[ "$current_command" == *"$(basename "$TARGET_PATH")"* ]] && is_existing_script_managed; then
log 'Existing cc-statusline-managed configuration detected. Updating in place.'
return 0
fi
printf 'Existing statusLine configuration detected:\n%s\n' "$current_json"
read -r -p 'Replace it with cc-statusline? [y/N] ' reply
case "$reply" in
y|Y|yes|YES) ;;
*)
log 'Installation cancelled by user.'
exit 0
;;
esac
}
save_previous_statusline_state() {
local previous_json timestamp
previous_json='null'
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date)
if [ -f "$SETTINGS_FILE" ] && settings_valid_json; then
previous_json=$("$JQ_BIN" -c '.statusLine // null' "$SETTINGS_FILE" 2>/dev/null || printf 'null')
fi
"$JQ_BIN" -n \
--arg savedAt "$timestamp" \
--arg platform "$EXPECTED_OS" \
--arg preset "$PRESET" \
--arg theme "$THEME" \
--arg iconStyle "$ICON_STYLE" \
--arg targetPath "$TARGET_PATH" \
--arg backupPath "$BACKUP_PATH" \
--arg command "$STATUSLINE_COMMAND" \
--arg sourceScript "$SOURCE_SCRIPT" \
--argjson previousStatusLine "$previous_json" \
'{
tool: "cc-statusline",
savedAt: $savedAt,
platform: $platform,
preset: $preset,
theme: $theme,
iconStyle: $iconStyle,
targetPath: $targetPath,
backupPath: $backupPath,
command: $command,
sourceScript: $sourceScript,
previousStatusLine: $previousStatusLine
}' > "$STATE_FILE"
}
backup_target() {
if [ -f "$TARGET_PATH" ]; then
cp "$TARGET_PATH" "$BACKUP_PATH"
log "Backed up existing script to $BACKUP_PATH"
fi
}
install_runtime_script() {
cp "$SOURCE_SCRIPT" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
log "Installed runtime script to $TARGET_PATH"
}
update_settings_with_jq() {
local tmp_file
tmp_file="$SETTINGS_FILE.tmp.$$"
if [ ! -f "$SETTINGS_FILE" ]; then
"$JQ_BIN" -n --arg cmd "$STATUSLINE_COMMAND" '{statusLine:{type:"command",command:$cmd,padding:0}}' > "$SETTINGS_FILE"
return 0
fi
settings_valid_json || return 1
"$JQ_BIN" --arg cmd "$STATUSLINE_COMMAND" '.statusLine = {type:"command", command:$cmd, padding:0}' "$SETTINGS_FILE" > "$tmp_file"
mv "$tmp_file" "$SETTINGS_FILE"
}
update_settings_with_python() {
local py
py=$(choose_python) || return 1
"$py" - "$SETTINGS_FILE" "$STATUSLINE_COMMAND" <<'PY'
import json
import os
import sys
settings_file = sys.argv[1]
command = sys.argv[2]
data = {}
if os.path.exists(settings_file):
with open(settings_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data['statusLine'] = {
'type': 'command',
'command': command,
'padding': 0,
}
with open(settings_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
}
update_settings() {
if update_settings_with_jq; then
log "Updated $SETTINGS_FILE"
return 0
fi
warn 'jq-based settings update failed. Attempting Python fallback.'
if update_settings_with_python; then
log "Updated $SETTINGS_FILE using Python fallback"
return 0
fi
fail_manual 'Failed to update settings.json automatically.'
}
print_summary() {
printf '\n'
printf 'Installed cc-statusline for %s\n' "$PLATFORM_NAME"
printf -- '- preset: %s\n' "$PRESET"
printf -- '- theme: %s\n' "$THEME"
printf -- '- icon style: %s\n' "$ICON_STYLE"
printf -- '- target: %s\n' "$TARGET_PATH"
printf -- '- command: %s\n' "$STATUSLINE_COMMAND"
printf -- '- previous statusLine snapshot: %s\n' "$STATE_FILE"
if [ -f "$BACKUP_PATH" ]; then
printf -- '- backup: %s\n' "$BACKUP_PATH"
fi
}
main() {
if [ "-" = '--help' ] || [ "-" = '-h' ]; then
usage
exit 0
fi
validate_choice
warn_if_unexpected_os
ensure_paths
ensure_jq
confirm_foreign_statusline
save_previous_statusline_state
backup_target
install_runtime_script
update_settings
print_summary
}
main "$@"
FILE:scripts/install_statusline_macos.sh
#!/usr/bin/env bash
set -euo pipefail
PLATFORM_NAME="macOS"
EXPECTED_OS="macos"
PRESET="-full"
THEME="-aurora"
ICON_STYLE="-classic"
TARGET_PATH="-$HOME/.claude/statusline.sh"
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
SOURCE_SCRIPT="$SCRIPT_DIR/statusline.sh"
INSTALL_JQ_SCRIPT="$SCRIPT_DIR/install_jq.sh"
CLAUDE_DIR="-$HOME/.claude"
SETTINGS_FILE="-$CLAUDE_DIR/settings.json"
STATE_FILE="-$CLAUDE_DIR/cc-statusline-state.json"
TARGET_DIR="$(dirname "$TARGET_PATH")"
BACKUP_PATH="$TARGET_DIR/$(basename "$TARGET_PATH").bak"
STATUSLINE_COMMAND="bash \"$TARGET_PATH\" \"$PRESET\" \"$THEME\" \"$ICON_STYLE\""
JQ_BIN=""
usage() {
printf 'Usage: bash scripts/install_statusline_macos.sh [preset] [theme] [icon_style] [target_path]\n'
printf 'Example: bash scripts/install_statusline_macos.sh full aurora classic "$HOME/.claude/statusline.sh"\n'
}
log() {
printf '[cc-statusline][%s] %s\n' "$PLATFORM_NAME" "$1"
}
warn() {
printf '[cc-statusline][%s][warn] %s\n' "$PLATFORM_NAME" "$1"
}
fail_manual() {
printf '[cc-statusline][%s][error] %s\n' "$PLATFORM_NAME" "$1" >&2
printf 'Manual fallback:\n' >&2
printf '1. Copy %s to %s\n' "$SOURCE_SCRIPT" "$TARGET_PATH" >&2
printf '2. Ensure jq is available at ~/.claude/jq.exe, ~/.claude/jq, or in PATH\n' >&2
printf '3. Update only the statusLine field in %s\n' "$SETTINGS_FILE" >&2
printf '4. Use this command value: %s\n' "$STATUSLINE_COMMAND" >&2
exit 1
}
validate_choice() {
case "$PRESET" in
full|standard|minimal|developer) ;;
*) fail_manual "Unsupported preset: $PRESET" ;;
esac
case "$THEME" in
aurora|sunset|ocean|mono) ;;
*) fail_manual "Unsupported theme: $THEME" ;;
esac
case "$ICON_STYLE" in
classic|minimal|developer) ;;
*) fail_manual "Unsupported icon style: $ICON_STYLE" ;;
esac
}
detect_os() {
case "$(uname -s 2>/dev/null)" in
Linux*) printf 'linux' ;;
Darwin*) printf 'macos' ;;
CYGWIN*|MINGW*|MSYS*) printf 'windows' ;;
*)
if [ -n "-" ]; then
printf 'windows'
else
printf 'unknown'
fi
;;
esac
}
warn_if_unexpected_os() {
local detected
detected=$(detect_os)
if [ "$detected" != "$EXPECTED_OS" ]; then
warn "This installer targets $PLATFORM_NAME, but detected $detected. Continuing anyway."
fi
}
ensure_paths() {
[ -f "$SOURCE_SCRIPT" ] || fail_manual "Runtime script not found: $SOURCE_SCRIPT"
mkdir -p "$CLAUDE_DIR" "$TARGET_DIR"
}
choose_jq_bin() {
if [ -x "$HOME/.claude/jq.exe" ] && "$HOME/.claude/jq.exe" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq.exe"
return 0
fi
if [ -x "$HOME/.claude/jq" ] && "$HOME/.claude/jq" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq"
return 0
fi
if command -v jq >/dev/null 2>&1; then
command -v jq
return 0
fi
return 1
}
ensure_jq() {
if JQ_BIN=$(choose_jq_bin); then
log "Using jq at $JQ_BIN"
return 0
fi
warn "jq not found. Attempting automatic install."
if [ -f "$INSTALL_JQ_SCRIPT" ]; then
bash "$INSTALL_JQ_SCRIPT" || true
fi
if JQ_BIN=$(choose_jq_bin); then
log "jq installed successfully at $JQ_BIN"
return 0
fi
fail_manual 'jq is required for the statusline runtime and could not be installed automatically.'
}
choose_python() {
if command -v python3 >/dev/null 2>&1; then
command -v python3
return 0
fi
if command -v python >/dev/null 2>&1; then
command -v python
return 0
fi
return 1
}
settings_valid_json() {
[ ! -f "$SETTINGS_FILE" ] && return 0
"$JQ_BIN" -e . "$SETTINGS_FILE" >/dev/null 2>&1
}
read_current_statusline_json() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -c '.statusLine // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
read_current_statusline_command() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -r '.statusLine.command // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
is_existing_script_managed() {
[ -f "$TARGET_PATH" ] || return 1
grep -q 'cc-statusline runtime script' "$TARGET_PATH" 2>/dev/null
}
confirm_foreign_statusline() {
[ -f "$SETTINGS_FILE" ] || return 0
settings_valid_json || fail_manual "settings.json is not valid JSON and cannot be updated safely."
local current_json current_command
current_json=$(read_current_statusline_json)
[ -z "$current_json" ] && return 0
current_command=$(read_current_statusline_command)
if [[ "$current_command" == *"$(basename "$TARGET_PATH")"* ]] && is_existing_script_managed; then
log 'Existing cc-statusline-managed configuration detected. Updating in place.'
return 0
fi
printf 'Existing statusLine configuration detected:\n%s\n' "$current_json"
read -r -p 'Replace it with cc-statusline? [y/N] ' reply
case "$reply" in
y|Y|yes|YES) ;;
*)
log 'Installation cancelled by user.'
exit 0
;;
esac
}
save_previous_statusline_state() {
local previous_json timestamp
previous_json='null'
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date)
if [ -f "$SETTINGS_FILE" ] && settings_valid_json; then
previous_json=$("$JQ_BIN" -c '.statusLine // null' "$SETTINGS_FILE" 2>/dev/null || printf 'null')
fi
"$JQ_BIN" -n \
--arg savedAt "$timestamp" \
--arg platform "$EXPECTED_OS" \
--arg preset "$PRESET" \
--arg theme "$THEME" \
--arg iconStyle "$ICON_STYLE" \
--arg targetPath "$TARGET_PATH" \
--arg backupPath "$BACKUP_PATH" \
--arg command "$STATUSLINE_COMMAND" \
--arg sourceScript "$SOURCE_SCRIPT" \
--argjson previousStatusLine "$previous_json" \
'{
tool: "cc-statusline",
savedAt: $savedAt,
platform: $platform,
preset: $preset,
theme: $theme,
iconStyle: $iconStyle,
targetPath: $targetPath,
backupPath: $backupPath,
command: $command,
sourceScript: $sourceScript,
previousStatusLine: $previousStatusLine
}' > "$STATE_FILE"
}
backup_target() {
if [ -f "$TARGET_PATH" ]; then
cp "$TARGET_PATH" "$BACKUP_PATH"
log "Backed up existing script to $BACKUP_PATH"
fi
}
install_runtime_script() {
cp "$SOURCE_SCRIPT" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
log "Installed runtime script to $TARGET_PATH"
}
update_settings_with_jq() {
local tmp_file
tmp_file="$SETTINGS_FILE.tmp.$$"
if [ ! -f "$SETTINGS_FILE" ]; then
"$JQ_BIN" -n --arg cmd "$STATUSLINE_COMMAND" '{statusLine:{type:"command",command:$cmd,padding:0}}' > "$SETTINGS_FILE"
return 0
fi
settings_valid_json || return 1
"$JQ_BIN" --arg cmd "$STATUSLINE_COMMAND" '.statusLine = {type:"command", command:$cmd, padding:0}' "$SETTINGS_FILE" > "$tmp_file"
mv "$tmp_file" "$SETTINGS_FILE"
}
update_settings_with_python() {
local py
py=$(choose_python) || return 1
"$py" - "$SETTINGS_FILE" "$STATUSLINE_COMMAND" <<'PY'
import json
import os
import sys
settings_file = sys.argv[1]
command = sys.argv[2]
data = {}
if os.path.exists(settings_file):
with open(settings_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data['statusLine'] = {
'type': 'command',
'command': command,
'padding': 0,
}
with open(settings_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
}
update_settings() {
if update_settings_with_jq; then
log "Updated $SETTINGS_FILE"
return 0
fi
warn 'jq-based settings update failed. Attempting Python fallback.'
if update_settings_with_python; then
log "Updated $SETTINGS_FILE using Python fallback"
return 0
fi
fail_manual 'Failed to update settings.json automatically.'
}
print_summary() {
printf '\n'
printf 'Installed cc-statusline for %s\n' "$PLATFORM_NAME"
printf -- '- preset: %s\n' "$PRESET"
printf -- '- theme: %s\n' "$THEME"
printf -- '- icon style: %s\n' "$ICON_STYLE"
printf -- '- target: %s\n' "$TARGET_PATH"
printf -- '- command: %s\n' "$STATUSLINE_COMMAND"
printf -- '- previous statusLine snapshot: %s\n' "$STATE_FILE"
if [ -f "$BACKUP_PATH" ]; then
printf -- '- backup: %s\n' "$BACKUP_PATH"
fi
}
main() {
if [ "-" = '--help' ] || [ "-" = '-h' ]; then
usage
exit 0
fi
validate_choice
warn_if_unexpected_os
ensure_paths
ensure_jq
confirm_foreign_statusline
save_previous_statusline_state
backup_target
install_runtime_script
update_settings
print_summary
}
main "$@"
FILE:scripts/install_statusline_windows.sh
#!/usr/bin/env bash
set -euo pipefail
PLATFORM_NAME="Windows"
EXPECTED_OS="windows"
PRESET="-full"
THEME="-aurora"
ICON_STYLE="-classic"
TARGET_PATH="-$HOME/.claude/statusline.sh"
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
SOURCE_SCRIPT="$SCRIPT_DIR/statusline.sh"
INSTALL_JQ_SCRIPT="$SCRIPT_DIR/install_jq.sh"
CLAUDE_DIR="-$HOME/.claude"
SETTINGS_FILE="-$CLAUDE_DIR/settings.json"
STATE_FILE="-$CLAUDE_DIR/cc-statusline-state.json"
TARGET_DIR="$(dirname "$TARGET_PATH")"
BACKUP_PATH="$TARGET_DIR/$(basename "$TARGET_PATH").bak"
STATUSLINE_COMMAND="bash \"$TARGET_PATH\" \"$PRESET\" \"$THEME\" \"$ICON_STYLE\""
JQ_BIN=""
usage() {
printf 'Usage: bash scripts/install_statusline_windows.sh [preset] [theme] [icon_style] [target_path]\n'
printf 'Example: bash scripts/install_statusline_windows.sh full aurora classic "$HOME/.claude/statusline.sh"\n'
}
log() {
printf '[cc-statusline][%s] %s\n' "$PLATFORM_NAME" "$1"
}
warn() {
printf '[cc-statusline][%s][warn] %s\n' "$PLATFORM_NAME" "$1"
}
fail_manual() {
printf '[cc-statusline][%s][error] %s\n' "$PLATFORM_NAME" "$1" >&2
printf 'Manual fallback:\n' >&2
printf '1. Copy %s to %s\n' "$SOURCE_SCRIPT" "$TARGET_PATH" >&2
printf '2. Ensure jq is available at ~/.claude/jq.exe, ~/.claude/jq, or in PATH\n' >&2
printf '3. Update only the statusLine field in %s\n' "$SETTINGS_FILE" >&2
printf '4. Use this command value: %s\n' "$STATUSLINE_COMMAND" >&2
exit 1
}
validate_choice() {
case "$PRESET" in
full|standard|minimal|developer) ;;
*) fail_manual "Unsupported preset: $PRESET" ;;
esac
case "$THEME" in
aurora|sunset|ocean|mono) ;;
*) fail_manual "Unsupported theme: $THEME" ;;
esac
case "$ICON_STYLE" in
classic|minimal|developer) ;;
*) fail_manual "Unsupported icon style: $ICON_STYLE" ;;
esac
}
detect_os() {
case "$(uname -s 2>/dev/null)" in
Linux*) printf 'linux' ;;
Darwin*) printf 'macos' ;;
CYGWIN*|MINGW*|MSYS*) printf 'windows' ;;
*)
if [ -n "-" ]; then
printf 'windows'
else
printf 'unknown'
fi
;;
esac
}
warn_if_unexpected_os() {
local detected
detected=$(detect_os)
if [ "$detected" != "$EXPECTED_OS" ]; then
warn "This installer targets $PLATFORM_NAME, but detected $detected. Continuing anyway."
fi
}
ensure_paths() {
[ -f "$SOURCE_SCRIPT" ] || fail_manual "Runtime script not found: $SOURCE_SCRIPT"
mkdir -p "$CLAUDE_DIR" "$TARGET_DIR"
}
choose_jq_bin() {
if [ -x "$HOME/.claude/jq.exe" ] && "$HOME/.claude/jq.exe" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq.exe"
return 0
fi
if [ -x "$HOME/.claude/jq" ] && "$HOME/.claude/jq" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq"
return 0
fi
if command -v jq >/dev/null 2>&1; then
command -v jq
return 0
fi
return 1
}
ensure_jq() {
if JQ_BIN=$(choose_jq_bin); then
log "Using jq at $JQ_BIN"
return 0
fi
warn "jq not found. Attempting automatic install."
if [ -f "$INSTALL_JQ_SCRIPT" ]; then
bash "$INSTALL_JQ_SCRIPT" || true
fi
if JQ_BIN=$(choose_jq_bin); then
log "jq installed successfully at $JQ_BIN"
return 0
fi
fail_manual 'jq is required for the statusline runtime and could not be installed automatically.'
}
choose_python() {
if command -v python3 >/dev/null 2>&1; then
command -v python3
return 0
fi
if command -v python >/dev/null 2>&1; then
command -v python
return 0
fi
return 1
}
settings_valid_json() {
[ ! -f "$SETTINGS_FILE" ] && return 0
"$JQ_BIN" -e . "$SETTINGS_FILE" >/dev/null 2>&1
}
read_current_statusline_json() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -c '.statusLine // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
read_current_statusline_command() {
[ -f "$SETTINGS_FILE" ] || return 0
"$JQ_BIN" -r '.statusLine.command // empty' "$SETTINGS_FILE" 2>/dev/null || true
}
is_existing_script_managed() {
[ -f "$TARGET_PATH" ] || return 1
grep -q 'cc-statusline runtime script' "$TARGET_PATH" 2>/dev/null
}
confirm_foreign_statusline() {
[ -f "$SETTINGS_FILE" ] || return 0
settings_valid_json || fail_manual "settings.json is not valid JSON and cannot be updated safely."
local current_json current_command
current_json=$(read_current_statusline_json)
[ -z "$current_json" ] && return 0
current_command=$(read_current_statusline_command)
if [[ "$current_command" == *"$(basename "$TARGET_PATH")"* ]] && is_existing_script_managed; then
log 'Existing cc-statusline-managed configuration detected. Updating in place.'
return 0
fi
printf 'Existing statusLine configuration detected:\n%s\n' "$current_json"
read -r -p 'Replace it with cc-statusline? [y/N] ' reply
case "$reply" in
y|Y|yes|YES) ;;
*)
log 'Installation cancelled by user.'
exit 0
;;
esac
}
save_previous_statusline_state() {
local previous_json timestamp
previous_json='null'
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date)
if [ -f "$SETTINGS_FILE" ] && settings_valid_json; then
previous_json=$("$JQ_BIN" -c '.statusLine // null' "$SETTINGS_FILE" 2>/dev/null || printf 'null')
fi
"$JQ_BIN" -n \
--arg savedAt "$timestamp" \
--arg platform "$EXPECTED_OS" \
--arg preset "$PRESET" \
--arg theme "$THEME" \
--arg iconStyle "$ICON_STYLE" \
--arg targetPath "$TARGET_PATH" \
--arg backupPath "$BACKUP_PATH" \
--arg command "$STATUSLINE_COMMAND" \
--arg sourceScript "$SOURCE_SCRIPT" \
--argjson previousStatusLine "$previous_json" \
'{
tool: "cc-statusline",
savedAt: $savedAt,
platform: $platform,
preset: $preset,
theme: $theme,
iconStyle: $iconStyle,
targetPath: $targetPath,
backupPath: $backupPath,
command: $command,
sourceScript: $sourceScript,
previousStatusLine: $previousStatusLine
}' > "$STATE_FILE"
}
backup_target() {
if [ -f "$TARGET_PATH" ]; then
cp "$TARGET_PATH" "$BACKUP_PATH"
log "Backed up existing script to $BACKUP_PATH"
fi
}
install_runtime_script() {
cp "$SOURCE_SCRIPT" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
log "Installed runtime script to $TARGET_PATH"
}
update_settings_with_jq() {
local tmp_file
tmp_file="$SETTINGS_FILE.tmp.$$"
if [ ! -f "$SETTINGS_FILE" ]; then
"$JQ_BIN" -n --arg cmd "$STATUSLINE_COMMAND" '{statusLine:{type:"command",command:$cmd,padding:0}}' > "$SETTINGS_FILE"
return 0
fi
settings_valid_json || return 1
"$JQ_BIN" --arg cmd "$STATUSLINE_COMMAND" '.statusLine = {type:"command", command:$cmd, padding:0}' "$SETTINGS_FILE" > "$tmp_file"
mv "$tmp_file" "$SETTINGS_FILE"
}
update_settings_with_python() {
local py
py=$(choose_python) || return 1
"$py" - "$SETTINGS_FILE" "$STATUSLINE_COMMAND" <<'PY'
import json
import os
import sys
settings_file = sys.argv[1]
command = sys.argv[2]
data = {}
if os.path.exists(settings_file):
with open(settings_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data['statusLine'] = {
'type': 'command',
'command': command,
'padding': 0,
}
with open(settings_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
}
update_settings() {
if update_settings_with_jq; then
log "Updated $SETTINGS_FILE"
return 0
fi
warn 'jq-based settings update failed. Attempting Python fallback.'
if update_settings_with_python; then
log "Updated $SETTINGS_FILE using Python fallback"
return 0
fi
fail_manual 'Failed to update settings.json automatically.'
}
print_summary() {
printf '\n'
printf 'Installed cc-statusline for %s\n' "$PLATFORM_NAME"
printf -- '- preset: %s\n' "$PRESET"
printf -- '- theme: %s\n' "$THEME"
printf -- '- icon style: %s\n' "$ICON_STYLE"
printf -- '- target: %s\n' "$TARGET_PATH"
printf -- '- command: %s\n' "$STATUSLINE_COMMAND"
printf -- '- previous statusLine snapshot: %s\n' "$STATE_FILE"
if [ -f "$BACKUP_PATH" ]; then
printf -- '- backup: %s\n' "$BACKUP_PATH"
fi
}
main() {
if [ "-" = '--help' ] || [ "-" = '-h' ]; then
usage
exit 0
fi
validate_choice
warn_if_unexpected_os
ensure_paths
ensure_jq
confirm_foreign_statusline
save_previous_statusline_state
backup_target
install_runtime_script
update_settings
print_summary
}
main "$@"
FILE:scripts/statusline.sh
#!/usr/bin/env bash
# cc-statusline runtime script
# Usage: bash statusline.sh [preset] [theme] [icon_style]
set -f
PRESET="-full"
THEME="-aurora"
ICON_STYLE="-classic"
CUSTOM_LAYOUT_MODE="-${CUSTOM_LAYOUT_MODE:-false}"
CUSTOM_THEME="-${CUSTOM_THEME:-}"
CUSTOM_ICON_STYLE="-${CUSTOM_ICON_STYLE:-}"
CUSTOM_LINE_1="-${CUSTOM_LINE_1:-}"
CUSTOM_LINE_2="-${CUSTOM_LINE_2:-}"
CUSTOM_LINE_3="-${CUSTOM_LINE_3:-}"
[ -n "$CUSTOM_THEME" ] && THEME="$CUSTOM_THEME"
[ -n "$CUSTOM_ICON_STYLE" ] && ICON_STYLE="$CUSTOM_ICON_STYLE"
[ "$PRESET" = "custom" ] && CUSTOM_LAYOUT_MODE="true"
ESC=$(printf '\033')
RESET="ESC[0m"
BOLD="ESC[1m"
DIM="ESC[2m"
JQ="$HOME/.claude/jq.exe"
[ ! -x "$JQ" ] && JQ="$HOME/.claude/jq"
[ ! -x "$JQ" ] && JQ="jq"
input=$(cat)
if [ -z "$input" ]; then
printf '✨ Claude Code'
exit 0
fi
if ! "$JQ" --version >/dev/null 2>&1; then
printf 'Claude Code | jq missing'
exit 0
fi
load_theme() {
case "$THEME" in
aurora|Aurora)
COLOR_MODEL="ESC[38;2;180;130;255m"
COLOR_EFFORT="ESC[38;2;200;160;255m"
COLOR_THINK="ESC[38;2;255;130;171m"
COLOR_FAST="ESC[38;2;180;230;80m"
COLOR_PERM_AUTO="ESC[38;2;72;201;176m"
COLOR_PERM_PLAN="ESC[38;2;250;215;90m"
COLOR_PERM_DEFAULT="ESC[38;2;100;149;237m"
COLOR_ACTIVE="ESC[38;2;80;200;120m"
COLOR_VERSION="ESC[38;2;72;201;176m"
COLOR_CONTEXT="ESC[38;2;0;206;209m"
COLOR_SKILLS="ESC[38;2;255;165;80m"
COLOR_MCP="ESC[38;2;0;206;209m"
COLOR_CWD="ESC[38;2;250;215;90m"
COLOR_GIT="ESC[38;2;80;200;120m"
COLOR_CTX_TOKENS="ESC[38;2;135;206;250m"
COLOR_SUM_TOKENS="ESC[38;2;200;160;255m"
COLOR_DURATION="ESC[38;2;135;206;250m"
COLOR_COST="ESC[38;2;255;165;80m"
COLOR_TEXT="ESC[38;2;220;220;230m"
COLOR_MUTED="ESC[38;2;130;130;145m"
COLOR_OK="ESC[38;2;80;200;120m"
COLOR_CAUTION="ESC[38;2;250;215;90m"
COLOR_WARN="ESC[38;2;255;165;80m"
COLOR_DANGER="ESC[38;2;255;100;100m"
;;
sunset|Sunset)
COLOR_MODEL="ESC[38;2;255;185;30m"
COLOR_EFFORT="ESC[38;2;255;175;50m"
COLOR_THINK="ESC[38;2;255;120;120m"
COLOR_FAST="ESC[38;2;255;210;60m"
COLOR_PERM_AUTO="ESC[38;2;255;160;100m"
COLOR_PERM_PLAN="ESC[38;2;255;140;40m"
COLOR_PERM_DEFAULT="ESC[38;2;255;100;80m"
COLOR_ACTIVE="ESC[38;2;255;210;60m"
COLOR_VERSION="ESC[38;2;255;160;100m"
COLOR_CONTEXT="ESC[38;2;255;140;40m"
COLOR_SKILLS="ESC[38;2;255;175;50m"
COLOR_MCP="ESC[38;2;255;160;100m"
COLOR_CWD="ESC[38;2;255;185;30m"
COLOR_GIT="ESC[38;2;255;210;60m"
COLOR_CTX_TOKENS="ESC[38;2;255;100;80m"
COLOR_SUM_TOKENS="ESC[38;2;255;175;50m"
COLOR_DURATION="ESC[38;2;255;160;100m"
COLOR_COST="ESC[38;2;255;80;60m"
COLOR_TEXT="ESC[38;2;255;240;210m"
COLOR_MUTED="ESC[38;2;160;130;110m"
COLOR_OK="ESC[38;2;255;210;60m"
COLOR_CAUTION="ESC[38;2;255;185;30m"
COLOR_WARN="ESC[38;2;255;140;40m"
COLOR_DANGER="ESC[38;2;255;80;60m"
;;
ocean|Ocean)
COLOR_MODEL="ESC[38;2;50;220;190m"
COLOR_EFFORT="ESC[38;2;0;200;160m"
COLOR_THINK="ESC[38;2;100;190;240m"
COLOR_FAST="ESC[38;2;100;240;180m"
COLOR_PERM_AUTO="ESC[38;2;80;210;160m"
COLOR_PERM_PLAN="ESC[38;2;0;220;220m"
COLOR_PERM_DEFAULT="ESC[38;2;30;144;255m"
COLOR_ACTIVE="ESC[38;2;100;240;180m"
COLOR_VERSION="ESC[38;2;50;220;190m"
COLOR_CONTEXT="ESC[38;2;0;220;220m"
COLOR_SKILLS="ESC[38;2;0;200;160m"
COLOR_MCP="ESC[38;2;100;190;240m"
COLOR_CWD="ESC[38;2;80;210;160m"
COLOR_GIT="ESC[38;2;50;220;190m"
COLOR_CTX_TOKENS="ESC[38;2;180;230;250m"
COLOR_SUM_TOKENS="ESC[38;2;0;200;160m"
COLOR_DURATION="ESC[38;2;100;190;240m"
COLOR_COST="ESC[38;2;0;220;220m"
COLOR_TEXT="ESC[38;2;180;230;250m"
COLOR_MUTED="ESC[38;2;100;140;160m"
COLOR_OK="ESC[38;2;100;240;180m"
COLOR_CAUTION="ESC[38;2;100;190;240m"
COLOR_WARN="ESC[38;2;0;220;220m"
COLOR_DANGER="ESC[38;2;30;144;255m"
;;
mono|Mono)
COLOR_MODEL="ESC[38;2;240;240;240m"
COLOR_EFFORT="ESC[38;2;200;200;200m"
COLOR_THINK="ESC[38;2;200;200;200m"
COLOR_FAST="ESC[38;2;240;240;240m"
COLOR_PERM_AUTO="ESC[38;2;200;200;200m"
COLOR_PERM_PLAN="ESC[38;2;160;160;160m"
COLOR_PERM_DEFAULT="ESC[38;2;160;160;160m"
COLOR_ACTIVE="ESC[38;2;240;240;240m"
COLOR_VERSION="ESC[38;2;160;160;160m"
COLOR_CONTEXT="ESC[38;2;200;200;200m"
COLOR_SKILLS="ESC[38;2;200;200;200m"
COLOR_MCP="ESC[38;2;160;160;160m"
COLOR_CWD="ESC[38;2;200;200;200m"
COLOR_GIT="ESC[38;2;200;200;200m"
COLOR_CTX_TOKENS="ESC[38;2;160;160;160m"
COLOR_SUM_TOKENS="ESC[38;2;160;160;160m"
COLOR_DURATION="ESC[38;2;160;160;160m"
COLOR_COST="ESC[38;2;200;200;200m"
COLOR_TEXT="ESC[38;2;240;240;240m"
COLOR_MUTED="ESC[38;2;120;120;120m"
COLOR_OK="ESC[38;2;240;240;240m"
COLOR_CAUTION="ESC[38;2;200;200;200m"
COLOR_WARN="ESC[38;2;160;160;160m"
COLOR_DANGER="ESC[38;2;120;120;120m"
;;
*)
THEME="aurora"
load_theme
;;
esac
}
load_icons() {
case "$ICON_STYLE" in
classic)
ICON_MODEL='✨'
ICON_EFFORT='⚡'
ICON_THINK='🧠'
ICON_FAST='🚀'
ICON_PERM_AUTO='🔓'
ICON_PERM_PLAN='🔐'
ICON_PERM_DEFAULT='🔒'
ICON_VERSION='⚙'
ICON_ACTIVE='●'
ICON_CONTEXT='🔋'
ICON_SKILLS='🛠'
ICON_MCP='🔌'
ICON_CWD='📂'
ICON_GIT='🌿'
ICON_CTX_TOKENS='💬'
ICON_SUM_TOKENS='📈'
ICON_API='⏱'
ICON_TTL='⏳'
ICON_COST='💰'
;;
minimal)
ICON_MODEL='M'
ICON_EFFORT='E'
ICON_THINK='T'
ICON_FAST='F'
ICON_PERM_AUTO='A'
ICON_PERM_PLAN='P'
ICON_PERM_DEFAULT='D'
ICON_VERSION='V'
ICON_ACTIVE='•'
ICON_CONTEXT='C'
ICON_SKILLS='S'
ICON_MCP='M'
ICON_CWD='@'
ICON_GIT='git'
ICON_CTX_TOKENS='I/O'
ICON_SUM_TOKENS='Σ'
ICON_API='api'
ICON_TTL='ttl'
ICON_COST='$'
;;
developer)
ICON_MODEL='λ'
ICON_EFFORT='≡'
ICON_THINK='∴'
ICON_FAST='≫'
ICON_PERM_AUTO='+'
ICON_PERM_PLAN='~'
ICON_PERM_DEFAULT='-'
ICON_VERSION='#'
ICON_ACTIVE='●'
ICON_CONTEXT='[]'
ICON_SKILLS='sk'
ICON_MCP='mc'
ICON_CWD='::'
ICON_GIT='git'
ICON_CTX_TOKENS='in'
ICON_SUM_TOKENS='Σ'
ICON_API='api'
ICON_TTL='all'
ICON_COST='$'
;;
*)
ICON_STYLE='classic'
load_icons
;;
esac
}
format_tokens() {
local num=$1
if [ "$num" -ge 1000000 ] 2>/dev/null; then
awk "BEGIN {printf \"%.1fM\", $num / 1000000}"
elif [ "$num" -ge 1000 ] 2>/dev/null; then
awk "BEGIN {printf \"%.1fK\", $num / 1000}"
else
printf '%d' "$num"
fi
}
pct_color() {
local pct=$1
if [ "$pct" -ge 90 ] 2>/dev/null; then
printf '%s' "$COLOR_DANGER"
elif [ "$pct" -ge 70 ] 2>/dev/null; then
printf '%s' "$COLOR_WARN"
elif [ "$pct" -ge 50 ] 2>/dev/null; then
printf '%s' "$COLOR_CAUTION"
else
printf '%s' "$COLOR_OK"
fi
}
progress_bar() {
local pct=$1
local width=12
[ "$pct" -lt 0 ] 2>/dev/null && pct=0
[ "$pct" -gt 100 ] 2>/dev/null && pct=100
local filled=$(( pct * width / 100 ))
local empty=$(( width - filled ))
local bar=''
local i
for (( i=0; i<filled; i++ )); do bar+="█"; done
for (( i=0; i<empty; i++ )); do bar+="░"; done
printf '%s' "$bar"
}
fmt_duration() {
local ms=$1
[ "$ms" -le 0 ] 2>/dev/null && { printf '0s'; return; }
local total_sec=$(( ms / 1000 ))
local min=$(( total_sec / 60 ))
local sec=$(( total_sec % 60 ))
if [ "$min" -gt 0 ]; then
printf '%dm%02ds' "$min" "$sec"
else
printf '%ds' "$sec"
fi
}
join_segments() {
local delimiter=$1
shift
local output=''
local segment
for segment in "$@"; do
[ -z "$segment" ] && continue
if [ -n "$output" ]; then
output+="$delimiter"
fi
output+="$segment"
done
printf '%s' "$output"
}
join_output_lines() {
local output=''
local line
for line in "$@"; do
[ -z "$line" ] && continue
if [ -n "$output" ]; then
output+=$'\n'
fi
output+="$line"
done
printf '%s' "$output"
}
module_segment() {
case "$1" in
model) printf '%s' "$seg_model" ;;
modes) printf '%s' "$seg_modes" ;;
version) printf '%s' "$seg_version" ;;
active) printf '%s' "$seg_active" ;;
context) printf '%s' "$seg_context" ;;
tools) printf '%s' "$seg_tools" ;;
cwd) printf '%s' "$seg_cwd" ;;
git) printf '%s' "$seg_git" ;;
ctx_tokens) printf '%s' "$seg_ctx_tokens" ;;
sum_tokens) printf '%s' "$seg_sum_tokens" ;;
duration) printf '%s' "$seg_duration" ;;
cost) printf '%s' "$seg_cost" ;;
*) printf '' ;;
esac
}
render_custom_line() {
local csv=$1
local old_ifs=$IFS
IFS=','
read -r -a modules <<< "$csv"
IFS=$old_ifs
local parts=()
local module trimmed segment
for module in "modules[@]"; do
trimmed=$(printf '%s' "$module" | tr -d '[:space:]')
[ -z "$trimmed" ] && continue
segment=$(module_segment "$trimmed")
[ -n "$segment" ] && parts+=("$segment")
done
join_segments "$SEP" "parts[@]"
}
load_theme
load_icons
SEP="COLOR_MUTED │ RESET"
DOT="COLOR_MUTED · RESET"
AR_UP='↑'
AR_DN='↓'
model_name=$("$JQ" -r '.model.display_name // "Claude"' <<< "$input" 2>/dev/null)
version=$("$JQ" -r '.version // empty' <<< "$input" 2>/dev/null)
ctx_size=$("$JQ" -r '.context_window.context_window_size // 200000' <<< "$input" 2>/dev/null)
[ "$ctx_size" -eq 0 ] 2>/dev/null && ctx_size=200000
ctx_input=$("$JQ" -r '.context_window.current_usage.input_tokens // 0' <<< "$input" 2>/dev/null)
ctx_cache_w=$("$JQ" -r '.context_window.current_usage.cache_creation_input_tokens // 0' <<< "$input" 2>/dev/null)
ctx_cache_r=$("$JQ" -r '.context_window.current_usage.cache_read_input_tokens // 0' <<< "$input" 2>/dev/null)
ctx_output=$("$JQ" -r '.context_window.current_usage.output_tokens // 0' <<< "$input" 2>/dev/null)
ctx_total_in=$(( ctx_input + ctx_cache_w + ctx_cache_r ))
[ "$ctx_size" -gt 0 ] 2>/dev/null && pct_used=$(( ctx_total_in * 100 / ctx_size )) || pct_used=0
[ "$pct_used" -gt 100 ] 2>/dev/null && pct_used=100
cum_raw_in=$("$JQ" -r '.context_window.total_input_tokens // 0' <<< "$input" 2>/dev/null)
cum_cache_w=$("$JQ" -r '.context_window.total_cache_creation_input_tokens // 0' <<< "$input" 2>/dev/null)
cum_cache_r=$("$JQ" -r '.context_window.total_cache_read_input_tokens // 0' <<< "$input" 2>/dev/null)
cum_output=$("$JQ" -r '.context_window.total_output_tokens // 0' <<< "$input" 2>/dev/null)
cum_total_in=$(( cum_raw_in + cum_cache_w + cum_cache_r ))
[ "$cum_total_in" -eq 0 ] 2>/dev/null && cum_total_in=$cum_raw_in
cum_all=$(( cum_total_in + cum_output ))
cwd=$("$JQ" -r '.cwd // .workspace.current_dir // empty' <<< "$input" 2>/dev/null)
full_path=''
if [ -n "$cwd" ]; then
display_dir="cwd##*[/\\]"
parent="cwd%[/\\]*"
parent_name="parent##*[/\\]"
if [ -n "$parent_name" ] && [ "$parent_name" != "$display_dir" ]; then
full_path="parent_name/display_dir"
else
full_path="$display_dir"
fi
fi
git_branch=''
git_staged_add=0
git_staged_del=0
git_unstaged_add=0
git_unstaged_del=0
git_untracked=0
git_clean=true
if [ -n "$cwd" ] && [ -d "$cwd" ]; then
git_branch=$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null)
if [ -n "$git_branch" ]; then
read -r git_staged_add git_staged_del < <(git -C "$cwd" diff --cached --numstat 2>/dev/null | awk '{a+=$1; d+=$2} END {printf "%d %d\n", a, d}')
read -r git_unstaged_add git_unstaged_del < <(git -C "$cwd" diff --numstat 2>/dev/null | awk '{a+=$1; d+=$2} END {printf "%d %d\n", a, d}')
git_untracked=$(git -C "$cwd" ls-files --others --exclude-standard 2>/dev/null | wc -l | tr -d ' ')
total_changes=$(( git_staged_add + git_staged_del + git_unstaged_add + git_unstaged_del + git_untracked ))
[ "$total_changes" -gt 0 ] && git_clean=false
fi
fi
settings_path="$HOME/.claude/settings.json"
project_settings="$cwd/.claude/settings.json"
effort_level="high"
[ -n "-" ] && effort_level="$CLAUDE_CODE_EFFORT_LEVEL"
if [ -f "$settings_path" ]; then
val=$("$JQ" -r '.effortLevel // empty' "$settings_path" 2>/dev/null)
[ -n "$val" ] && effort_level="$val"
fi
thinking_enabled="true"
if [ -f "$settings_path" ]; then
val=$("$JQ" -r '.alwaysThinkingEnabled // empty' "$settings_path" 2>/dev/null)
[ -n "$val" ] && thinking_enabled="$val"
fi
perm_mode="default"
if [ -f "$project_settings" ]; then
val=$("$JQ" -r '.permissions.defaultMode // .permissions.allow_mode // empty' "$project_settings" 2>/dev/null)
[ -n "$val" ] && perm_mode="$val"
fi
if [ "$perm_mode" = "default" ] && [ -f "$settings_path" ]; then
val=$("$JQ" -r '.permissions.defaultMode // .permissions.allow_mode // empty' "$settings_path" 2>/dev/null)
[ -n "$val" ] && perm_mode="$val"
fi
fast_mode="false"
if [ -f "$settings_path" ]; then
val=$("$JQ" -r '.fastMode // empty' "$settings_path" 2>/dev/null)
[ "$val" = "true" ] && fast_mode="true"
fi
mcp_count=0
if [ -f "$settings_path" ]; then
val=$("$JQ" -r '.mcpServers // {} | keys | length' "$settings_path" 2>/dev/null)
[ -n "$val" ] && mcp_count=$val
fi
if [ -f "$project_settings" ]; then
val=$("$JQ" -r '.mcpServers // {} | keys | length' "$project_settings" 2>/dev/null)
[ -n "$val" ] && mcp_count=$(( mcp_count + val ))
fi
skills_count=0
skills_dir="$HOME/.claude/skills"
[ -d "$skills_dir" ] && skills_count=$(ls -1 "$skills_dir" 2>/dev/null | wc -l | tr -d ' ')
session_cost=$("$JQ" -r '.cost.total_cost_usd // empty' <<< "$input" 2>/dev/null)
if [ -n "$session_cost" ] && [ "$session_cost" != "null" ]; then
session_cost=$(awk "BEGIN {printf \"%.2f\", $session_cost}" 2>/dev/null)
fi
api_duration_ms=$("$JQ" -r '.cost.total_api_duration_ms // 0' <<< "$input" 2>/dev/null)
total_duration_ms=$("$JQ" -r '.cost.total_duration_ms // 0' <<< "$input" 2>/dev/null)
seg_model="COLOR_MODELBOLDICON_MODELRESET COLOR_MODELmodel_nameRESET"
case "$effort_level" in
low) effort_text='Low' ;;
medium) effort_text='Med' ;;
high) effort_text='High' ;;
max) effort_text='Max' ;;
*) effort_text="$effort_level" ;;
esac
seg_effort="COLOR_EFFORTICON_EFFORTRESET COLOR_EFFORTeffort_textRESET"
if [ "$thinking_enabled" = "true" ]; then
seg_think="COLOR_THINKICON_THINKRESET COLOR_THINKThinkRESET"
else
seg_think="COLOR_MUTEDICON_THINKRESET COLOR_MUTEDOffRESET"
fi
if [ "$fast_mode" = "true" ]; then
seg_fast="COLOR_FASTICON_FASTRESET COLOR_FASTFastRESET"
else
seg_fast="COLOR_MUTEDICON_FASTRESET COLOR_MUTEDNormalRESET"
fi
case "$perm_mode" in
auto-accept|auto) seg_perm="COLOR_PERM_AUTOICON_PERM_AUTORESET COLOR_PERM_AUTOAutoRESET" ;;
plan|plan-mode) seg_perm="COLOR_PERM_PLANICON_PERM_PLANRESET COLOR_PERM_PLANPlanRESET" ;;
*) seg_perm="COLOR_PERM_DEFAULTICON_PERM_DEFAULTRESET COLOR_PERM_DEFAULTDefaultRESET" ;;
esac
seg_modes=$(join_segments "$DOT" "$seg_effort" "$seg_think" "$seg_fast" "$seg_perm")
if [ -n "$version" ] && [ "$version" != "null" ]; then
seg_version="COLOR_VERSIONICON_VERSIONRESET COLOR_VERSIONvversionRESET"
else
seg_version="COLOR_MUTEDICON_VERSIONRESET COLOR_MUTED--RESET"
fi
seg_active="COLOR_ACTIVEICON_ACTIVERESET COLOR_ACTIVEActiveRESET"
bc=$(pct_color "$pct_used")
bar=$(progress_bar "$pct_used")
seg_context="COLOR_CONTEXTICON_CONTEXTRESET bc$(format_tokens "$ctx_total_in")COLOR_MUTED/RESETCOLOR_TEXT$(format_tokens "$ctx_size")RESET bcbar pct_used%RESET"
if [ "$skills_count" -gt 0 ]; then
seg_skills="COLOR_SKILLSICON_SKILLSRESET COLOR_SKILLSSkills:skills_countRESET"
else
seg_skills="COLOR_MUTEDICON_SKILLSRESET COLOR_MUTEDSkills:0RESET"
fi
if [ "$mcp_count" -gt 0 ]; then
seg_mcp="COLOR_MCPICON_MCPRESET COLOR_MCPMCP:mcp_countRESET"
else
seg_mcp="COLOR_MUTEDICON_MCPRESET COLOR_MUTEDMCP:0RESET"
fi
seg_tools=$(join_segments "$DOT" "$seg_skills" "$seg_mcp")
if [ -n "$full_path" ]; then
seg_cwd="COLOR_CWDICON_CWDRESET COLOR_CWDfull_pathRESET"
else
seg_cwd="COLOR_CWDICON_CWDRESET DIM~RESET"
fi
if [ -n "$git_branch" ]; then
git_status=''
if $git_clean; then
git_status="COLOR_OK✓RESET"
else
parts=''
sa=$(( git_staged_add + git_unstaged_add ))
sd=$(( git_staged_del + git_unstaged_del ))
[ "$sa" -gt 0 ] && parts+="COLOR_OK+saRESET"
[ "$sd" -gt 0 ] && parts+="+COLOR_DANGER-sdRESET"
[ "$git_untracked" -gt 0 ] && parts+="+COLOR_WARN?git_untrackedRESET"
git_status="DIM(RESETpartsDIM)RESET"
fi
seg_git="COLOR_GITICON_GITRESET COLOR_GITgit_branchRESET git_status"
else
seg_git="COLOR_MUTEDICON_GITRESET COLOR_MUTEDno repoRESET"
fi
seg_ctx_tokens="COLOR_CTX_TOKENSICON_CTX_TOKENSRESET COLOR_CTX_TOKENSCtxRESET COLOR_OKAR_UPRESETCOLOR_TEXT$(format_tokens "$ctx_total_in")RESET COLOR_WARNAR_DNRESETCOLOR_TEXT$(format_tokens "$ctx_output")RESET"
seg_sum_tokens="COLOR_SUM_TOKENSICON_SUM_TOKENSRESET COLOR_SUM_TOKENSSumRESET COLOR_OKAR_UPRESETCOLOR_TEXT$(format_tokens "$cum_total_in")RESET COLOR_WARNAR_DNRESETCOLOR_TEXT$(format_tokens "$cum_output")RESET DIM(RESETCOLOR_SUM_TOKENS$(format_tokens "$cum_all")RESETDIM)RESET"
seg_duration=$(join_segments "$DOT" \
"COLOR_DURATIONICON_APIRESET COLOR_DURATIONAPIRESET COLOR_TEXT$(fmt_duration "$api_duration_ms")RESET" \
"COLOR_DURATIONICON_TTLRESET COLOR_DURATIONTTLRESET COLOR_TEXT$(fmt_duration "$total_duration_ms")RESET")
seg_cost=''
if [ -n "$session_cost" ] && [ "$session_cost" != "null" ] && [ "$session_cost" != "0.00" ]; then
seg_cost="COLOR_COSTICON_COSTRESET COLOR_COST\$session_costRESET"
fi
line_full_1=$(join_segments "$SEP" "$seg_model" "$seg_modes" "$seg_version" "$seg_active")
line_full_2=$(join_segments "$SEP" "$seg_context" "$seg_tools" "$seg_cwd" "$seg_git")
line_full_3=$(join_segments "$SEP" "$seg_ctx_tokens" "$seg_sum_tokens" "$seg_duration" "$seg_cost")
line_standard_1="$line_full_1"
line_standard_2="$line_full_2"
line_minimal_1=$(join_segments "$SEP" "$seg_model" "$seg_version" "$seg_active" "$seg_cost")
line_developer_1=$(join_segments "$SEP" "$seg_model" "$seg_modes" "$seg_active")
line_developer_2=$(join_segments "$SEP" "$seg_cwd" "$seg_git" "$seg_context")
line_developer_3=$(join_segments "$SEP" "$seg_ctx_tokens" "$seg_sum_tokens" "$seg_duration" "$seg_cost")
if [ "$CUSTOM_LAYOUT_MODE" = "true" ]; then
custom_line_1=$(render_custom_line "$CUSTOM_LINE_1")
custom_line_2=$(render_custom_line "$CUSTOM_LINE_2")
custom_line_3=$(render_custom_line "$CUSTOM_LINE_3")
custom_output=$(join_output_lines "$custom_line_1" "$custom_line_2" "$custom_line_3")
if [ -n "$custom_output" ]; then
printf '%s' "$custom_output"
exit 0
fi
fi
case "$PRESET" in
full)
printf '%s\n%s\n%s' "$line_full_1" "$line_full_2" "$line_full_3"
;;
standard)
printf '%s\n%s' "$line_standard_1" "$line_standard_2"
;;
minimal)
printf '%s' "$line_minimal_1"
;;
developer)
printf '%s\n%s\n%s' "$line_developer_1" "$line_developer_2" "$line_developer_3"
;;
*)
printf '%s\n%s\n%s' "$line_full_1" "$line_full_2" "$line_full_3"
;;
esac
FILE:scripts/uninstall_statusline.sh
#!/usr/bin/env bash
set -euo pipefail
CLAUDE_DIR="-$HOME/.claude"
SETTINGS_FILE="-$CLAUDE_DIR/settings.json"
STATE_FILE="-$CLAUDE_DIR/cc-statusline-state.json"
log() {
printf '[cc-statusline][uninstall] %s\n' "$1"
}
warn() {
printf '[cc-statusline][uninstall][warn] %s\n' "$1"
}
choose_jq_bin() {
if [ -x "$HOME/.claude/jq.exe" ] && "$HOME/.claude/jq.exe" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq.exe"
return 0
fi
if [ -x "$HOME/.claude/jq" ] && "$HOME/.claude/jq" --version >/dev/null 2>&1; then
printf '%s' "$HOME/.claude/jq"
return 0
fi
if command -v jq >/dev/null 2>&1; then
command -v jq
return 0
fi
return 1
}
choose_python() {
if command -v python3 >/dev/null 2>&1; then
command -v python3
return 0
fi
if command -v python >/dev/null 2>&1; then
command -v python
return 0
fi
return 1
}
settings_has_statusline_jq() {
local jq_bin=$1
[ -f "$SETTINGS_FILE" ] || return 1
"$jq_bin" -e '.statusLine != null' "$SETTINGS_FILE" >/dev/null 2>&1
}
remove_with_jq() {
local jq_bin=$1
local tmp_file
tmp_file="$SETTINGS_FILE.tmp.$$"
"$jq_bin" -e . "$SETTINGS_FILE" >/dev/null 2>&1 || return 1
"$jq_bin" 'del(.statusLine)' "$SETTINGS_FILE" > "$tmp_file"
mv "$tmp_file" "$SETTINGS_FILE"
}
remove_with_python() {
local py
py=$(choose_python) || return 1
"$py" - "$SETTINGS_FILE" <<'PY'
import json
import sys
settings_file = sys.argv[1]
with open(settings_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data.pop('statusLine', None)
with open(settings_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
}
print_restore_hint() {
if [ -f "$STATE_FILE" ]; then
log "Previous statusLine snapshot remains available at $STATE_FILE"
local jq_bin
if jq_bin=$(choose_jq_bin); then
local previous
previous=$("$jq_bin" -c '.previousStatusLine // null' "$STATE_FILE" 2>/dev/null || printf 'null')
log "Saved previous statusLine value: $previous"
fi
else
warn 'No saved previous statusLine snapshot was found.'
fi
}
main() {
if [ ! -f "$SETTINGS_FILE" ]; then
log "No settings.json found at $SETTINGS_FILE. Nothing to remove."
exit 0
fi
local jq_bin
if jq_bin=$(choose_jq_bin); then
if ! settings_has_statusline_jq "$jq_bin"; then
log 'settings.json does not contain a statusLine entry. Nothing to remove.'
exit 0
fi
if remove_with_jq "$jq_bin"; then
log 'Removed only the statusLine field from settings.json.'
print_restore_hint
log 'Generated script files were kept on disk.'
exit 0
fi
warn 'jq-based uninstall failed. Attempting Python fallback.'
fi
if remove_with_python; then
log 'Removed only the statusLine field from settings.json using Python fallback.'
print_restore_hint
log 'Generated script files were kept on disk.'
exit 0
fi
warn 'Automatic uninstall failed.'
warn 'Manual fallback: remove only the statusLine field from ~/.claude/settings.json and keep script files as desired.'
exit 1
}
main "$@"
FILE:themes/aurora.json
{
"id": "aurora",
"label_en": "Aurora",
"label_zh": "极光",
"description_en": "Blue-purple palette based on the current default Miluer visual style.",
"description_zh": "基于当前默认风格的蓝紫色主题。"
}
FILE:themes/mono.json
{
"id": "mono",
"label_en": "Mono",
"label_zh": "单色",
"description_en": "Minimal monochrome palette with lower visual noise.",
"description_zh": "低干扰的黑白灰单色主题。"
}
FILE:themes/ocean.json
{
"id": "ocean",
"label_en": "Ocean",
"label_zh": "海洋",
"description_en": "Cool cyan-blue-green palette for a calm technical look.",
"description_zh": "偏冷的青蓝绿配色,视觉更冷静、技术感更强。"
}
FILE:themes/sunset.json
{
"id": "sunset",
"label_en": "Sunset",
"label_zh": "日落",
"description_en": "Warm orange-yellow-red palette with a lively look.",
"description_zh": "偏暖的橙黄红配色,更有活力。"
}