سفارشیسازیِ نوارِ وضعیت
نوارِ وضعیت (status line) یک نوارِ سفارشی در پایینِ Claude Code است که هر اسکریپتِ شِلی که پیکربندی کنی را اجرا میکند. این نوار دادههای JSON نشست را روی stdin دریافت میکند و هر چیزی که اسکریپتت چاپ کند را نمایش میدهد؛ یعنی یک نمای دائمی و یکنگاهی از مصرفِ کانتکست، هزینهها، وضعیت git یا هر چیز دیگری که بخواهی پیگیری کنی به تو میدهد.
نوارهای وضعیت وقتی به کارت میآیند که:
- بخواهی هنگام کار، مصرفِ پنجرهی کانتکست را زیرِ نظر داشته باشی
- لازم باشد هزینههای نشست را دنبال کنی
- روی چند نشست همزمان کار میکنی و باید بتوانی آنها را از هم تشخیص بدهی
- بخواهی شاخهی git و وضعیتش همیشه پیدا باشد
این هم نمونهای از یک نوارِ وضعیتِ چندخطی که اطلاعاتِ git را در خطِ اول و یک نوارِ کانتکستِ رنگی را در خطِ دوم نشان میدهد.
این صفحه راهاندازیِ یک نوارِ وضعیتِ پایه را مرحلهبهمرحله نشان میدهد، توضیح میدهد دادهها چطور جریان پیدا میکنند از Claude Code به اسکریپتت، همهی فیلدهایی که میتوانی نمایش بدهی را فهرست میکند، و نمونههای آمادهی استفاده برای الگوهای رایج مثل وضعیت git، پیگیریِ هزینه و نوارهای پیشرفت ارائه میدهد.
راهاندازیِ یک نوارِ وضعیت
Section titled “راهاندازیِ یک نوارِ وضعیت”از دستورِ /statusline استفاده کن تا Claude Code خودش برایت یک اسکریپت بسازد، یا دستی یک اسکریپت بساز و به تنظیماتت اضافه کن.
استفاده از دستورِ /statusline
Section titled “استفاده از دستورِ /statusline”دستورِ /statusline دستورالعملهای زبانِ طبیعی را میپذیرد که توصیف میکنند چه چیزی میخواهی نمایش داده شود. Claude Code یک فایلِ اسکریپت در ~/.claude/ میسازد و تنظیماتت را خودکار بهروزرسانی میکند:
/statusline show model name and context percentage with a progress barپیکربندیِ دستیِ یک نوارِ وضعیت
Section titled “پیکربندیِ دستیِ یک نوارِ وضعیت”یک فیلدِ statusLine به تنظیماتِ کاربریات (~/.claude/settings.json، که در آن ~ پوشهی خانگیِ توست) یا تنظیماتِ پروژه اضافه کن. type را روی "command" بگذار و command را به مسیرِ یک اسکریپت یا یک دستورِ شِلِ خطی اشاره بده. برای یک راهنمای کامل از ساختنِ اسکریپت، ساختِ یک نوارِ وضعیت قدمبهقدم را ببین.
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh", "padding": 2 }}فیلدِ command در یک شِل اجرا میشود، پس میتوانی بهجای فایلِ اسکریپت از دستورهای خطی هم استفاده کنی. این نمونه از jq برای تجزیهی ورودیِ JSON و نمایشِ نامِ مدل و درصدِ کانتکست استفاده میکند:
{ "statusLine": { "type": "command", "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'" }}فیلدِ اختیاریِ padding فاصلهی افقیِ اضافی (به تعدادِ کاراکتر) به محتوای نوارِ وضعیت اضافه میکند. پیشفرضش 0 است. این فاصله علاوه بر فاصلهی توکارِ رابطِ کاربری است، پس تورفتگیِ نسبی را کنترل میکند نه فاصلهی مطلق از لبهی ترمینال.
فیلدِ اختیاریِ refreshInterval دستورت را علاوه بر بهروزرسانیهای رویدادمحور هر N ثانیه یکبار دوباره اجرا میکند. کمینهاش 1 است. این را وقتی تنظیم کن که نوارِ وضعیتت دادهی زمانمحور مثل ساعت نشان میدهد، یا وقتی سابایجنتهای پسزمینه وضعیتِ git را تغییر میدهند در حالی که نشستِ اصلی بیکار است. اگر بخواهی فقط روی رویدادها اجرا شود، آن را تنظیمنشده بگذار.
فیلدِ اختیاریِ hideVimModeIndicator متنِ توکارِ -- INSERT -- زیرِ پرامپت را پنهان میکند. این را روی true بگذار وقتی اسکریپتت خودش vim.mode را رندر میکند، تا حالت دو بار نشان داده نشود.
غیرفعالکردنِ نوارِ وضعیت
Section titled “غیرفعالکردنِ نوارِ وضعیت”/statusline را اجرا کن و از آن بخواه نوارِ وضعیتت را حذف یا پاک کند (مثلاً /statusline delete، /statusline clear، /statusline remove it). میتوانی فیلدِ statusLine را هم بهصورت دستی از settings.json حذف کنی.
ساختِ یک نوارِ وضعیت قدمبهقدم
Section titled “ساختِ یک نوارِ وضعیت قدمبهقدم”این راهنما با ساختنِ دستیِ یک نوارِ وضعیت که مدلِ فعلی، پوشهی کاری و درصدِ مصرفِ پنجرهی کانتکست را نمایش میدهد، نشان میدهد پشتِ پرده چه میگذرد.
این نمونهها از اسکریپتهای Bash استفاده میکنند که روی macOS و Linux کار میکنند. روی Windows، برای نمونههای PowerShell و Git Bash به پیکربندیِ Windows مراجعه کن.
یک اسکریپت بساز که JSON بخواند و خروجی چاپ کند
Claude Code دادههای JSON را از طریقِ stdin به اسکریپتت میفرستد. این اسکریپت از jq — یک تجزیهگرِ JSON خطِ فرمانی که شاید لازم باشد نصبش کنی — برای استخراجِ نامِ مدل، پوشه و درصدِ کانتکست استفاده میکند، و بعد یک خطِ قالببندیشده چاپ میکند.
این را در ~/.claude/statusline.sh ذخیره کن (که در آن ~ پوشهی خانگیِ توست، مثلاً /Users/username روی macOS یا /home/username روی Linux):
#!/bin/bash# Read JSON data that Claude Code sends to stdininput=$(cat)
# Extract fields using jqMODEL=$(echo "$input" | jq -r '.model.display_name')DIR=$(echo "$input" | jq -r '.workspace.current_dir')# The "// 0" provides a fallback if the field is nullPCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Output the status line - ${DIR##*/} extracts just the folder nameecho "[$MODEL] 📁 ${DIR##*/} | ${PCT}% context"آن را اجراپذیر کن
اسکریپت را اجراپذیر علامت بزن تا شِلت بتواند آن را اجرا کند:
chmod +x ~/.claude/statusline.shبه تنظیمات اضافه کن
به Claude Code بگو اسکریپتت را بهعنوانِ نوارِ وضعیت اجرا کند. این پیکربندی را به ~/.claude/settings.json اضافه کن، که type را روی "command" میگذارد (یعنی «این دستورِ شِل را اجرا کن») و command را به اسکریپتت اشاره میدهد:
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh" }}نوارِ وضعیتت در پایینِ رابطِ کاربری ظاهر میشود. تنظیمات خودکار دوباره بارگذاری میشوند، اما تغییرات تا تعاملِ بعدیات با Claude Code نمایان نمیشوند.
نوارهای وضعیت چطور کار میکنند
Section titled “نوارهای وضعیت چطور کار میکنند”Claude Code اسکریپتت را اجرا میکند و دادههای JSON نشست را از طریقِ stdin به آن میفرستد (pipe). اسکریپتت JSON را میخواند، آنچه را لازم دارد استخراج میکند، و متن را روی stdout چاپ میکند. Claude Code هر چیزی که اسکریپتت چاپ کند را نمایش میدهد.
کِی بهروز میشود
اسکریپتت بعد از هر پیامِ تازهی دستیار، پس از پایانِ /compact، هنگامِ تغییرِ حالتِ دسترسی، یا هنگامِ تغییرِ حالتِ vim اجرا میشود. بهروزرسانیها با تأخیرِ ۳۰۰ میلیثانیهای debounce میشوند، یعنی تغییراتِ سریع با هم دسته میشوند و اسکریپتت وقتی اوضاع آرام شد یکبار اجرا میشود. اگر در حینِ اجرای اسکریپت یک بهروزرسانیِ جدید رخ بدهد، اجرای در جریان لغو میشود. اگر اسکریپتت را ویرایش کنی، تغییرات تا وقتی تعاملِ بعدیات با Claude Code یک بهروزرسانی را تحریک کند، نمایان نمیشوند.
این محرکها میتوانند وقتی نشستِ اصلی بیکار است ساکت بمانند، مثلاً وقتی یک هماهنگکننده منتظرِ سابایجنتهای پسزمینه است. برای اینکه بخشهای زمانمحور یا منبعگرفته از بیرون در دورههای بیکاری بهروز بمانند، refreshInterval را تنظیم کن تا دستور را روی یک تایمرِ ثابت هم دوباره اجرا کند.
اسکریپتت چه چیزی میتواند خروجی بدهد
- چند خط: هر دستورِ
echoیاprintبهعنوانِ یک ردیفِ جداگانه نمایش داده میشود. نمونهی چندخطی را ببین. - رنگها: از کدهای فرارِ ANSI مثل
\033[32mبرای سبز استفاده کن (ترمینال باید پشتیبانی کند). نمونهی وضعیت git را ببین. - لینکها: از توالیهای فرارِ OSC 8 استفاده کن تا متن قابلِ کلیک شود (Cmd+کلیک روی macOS، Ctrl+کلیک روی Windows/Linux). نیاز به ترمینالی دارد که از hyperlink پشتیبانی کند مثل iTerm2، Kitty یا WezTerm. نمونهی لینکهای قابلِ کلیک را ببین.
اندازهکردنِ خروجی با ترمینال
Claude Code خروجیِ اسکریپتت را میگیرد بهجای آنکه آن را مستقیم به ترمینال وصل کند، پس tput cols و تشخیصِ عرض در سطحِ زبان نمیتوانند اندازهی ترمینال را از داخلِ اسکریپت بخوانند. {/* min-version: 2.1.153 */}بهجایش متغیرهای محیطیِ COLUMNS و LINES را بخوان. Claude Code اینها را پیش از اجرای اسکریپتت روی ابعادِ فعلیِ ترمینال تنظیم میکند. نیاز به Claude Code v2.1.153 یا بالاتر دارد.
دادههای در دسترس
Section titled “دادههای در دسترس”Claude Code فیلدهای JSON زیر را از طریقِ stdin به اسکریپتت میفرستد:
| فیلد | توضیح |
|---|---|
model.id, model.display_name | شناسهی مدلِ فعلی و نامِ نمایشی |
cwd, workspace.current_dir | پوشهی کاریِ فعلی. هر دو فیلد یک مقدار دارند؛ workspace.current_dir برای هماهنگی با workspace.project_dir ترجیح داده میشود. |
workspace.project_dir | پوشهای که Claude Code از آن راهاندازی شده، که اگر پوشهی کاری در حینِ نشست تغییر کند ممکن است با cwd فرق کند |
workspace.added_dirs | پوشههای اضافی که با /add-dir یا --add-dir افزوده شدهاند. اگر هیچکدام افزوده نشده باشد، آرایهی خالی است |
workspace.git_worktree | نامِ git worktree وقتی پوشهی فعلی داخلِ یک worktreeِ پیوندی است که با git worktree add ساخته شده. در درختِ کاریِ اصلی غایب است. برای هر git worktree پر میشود، برخلافِ worktree.* که فقط برای نشستهای --worktree کاربرد دارد |
workspace.repo.host, workspace.repo.owner, workspace.repo.name | هویتِ مخزن که از remoteِ origin تجزیه میشود، مثلاً "github.com", "anthropics", "claude-code". خارج از یک مخزنِ git یا وقتی هیچ remoteِ origin پیکربندی نشده، غایب است |
cost.total_cost_usd | هزینهی تخمینیِ نشست به دلار، که سمتِ کلاینت محاسبه میشود. ممکن است با صورتحسابِ واقعیات فرق کند |
cost.total_duration_ms | زمانِ کلِ سپریشده از شروعِ نشست، به میلیثانیه |
cost.total_api_duration_ms | زمانِ کلِ صرفشده برای انتظارِ پاسخهای API به میلیثانیه |
cost.total_lines_added, cost.total_lines_removed | خطوطِ کدِ تغییریافته |
context_window.total_input_tokens, context_window.total_output_tokens | تعدادِ توکنهایی که اکنون در پنجرهی کانتکست هستند، از آخرین پاسخِ API. ورودی شاملِ خواندن و نوشتنِ کش است. {/* min-version: 2.1.132 */}پیش از v2.1.132 اینها مجموعِ انباشتیِ نشست بودند |
context_window.context_window_size | بیشینهی اندازهی پنجرهی کانتکست به توکن. پیشفرض ۲۰۰۰۰۰، یا ۱۰۰۰۰۰۰ برای مدلهای با کانتکستِ گسترده. |
context_window.used_percentage | درصدِ ازپیشمحاسبهشدهی پنجرهی کانتکستِ مصرفشده |
context_window.remaining_percentage | درصدِ ازپیشمحاسبهشدهی پنجرهی کانتکستِ باقیمانده |
context_window.current_usage | تعدادِ توکنها از آخرین فراخوانیِ API، که در فیلدهای پنجرهی کانتکست توضیح داده شده |
exceeds_200k_tokens | اینکه آیا مجموعِ تعدادِ توکنها (ورودی، کش و خروجی با هم) از آخرین پاسخِ API از ۲۰۰هزار فراتر میرود یا نه. این یک آستانهی ثابت است صرفنظر از اندازهی واقعیِ پنجرهی کانتکست. |
effort.level | تلاشِ استدلالیِ فعلی (low, medium, high, xhigh یا max). مقدارِ زندهی نشست را بازتاب میدهد، از جمله تغییراتِ /effort در میانهی نشست. Ultracode یک سطحِ مجزا نیست و بهصورتِ xhigh گزارش میشود. وقتی مدلِ فعلی پارامترِ effort را پشتیبانی نکند، غایب است |
thinking.enabled | اینکه آیا تفکرِ گسترده (extended thinking) برای نشست فعال است یا نه |
rate_limits.five_hour.used_percentage, rate_limits.seven_day.used_percentage | درصدِ مصرفشدهی محدودیتِ نرخِ ۵ساعته یا ۷روزه، از ۰ تا ۱۰۰ |
rate_limits.five_hour.resets_at, rate_limits.seven_day.resets_at | ثانیههای Unix epoch وقتی پنجرهی محدودیتِ نرخِ ۵ساعته یا ۷روزه بازنشانی میشود |
session_id | شناسهی یکتای نشست |
session_name | نامِ سفارشیِ نشست که با پرچمِ --name یا /rename تنظیم شده. اگر هیچ نامِ سفارشیای تنظیم نشده باشد، غایب است |
transcript_path | مسیرِ فایلِ رونوشتِ گفتوگو |
version | نسخهی Claude Code |
output_style.name | نامِ سبکِ خروجیِ فعلی |
vim.mode | حالتِ فعلیِ vim (NORMAL, INSERT, VISUAL یا VISUAL LINE) وقتی حالتِ vim فعال است |
agent.name | نامِ ایجنت وقتی با پرچمِ --agent یا با تنظیماتِ ایجنتِ پیکربندیشده اجرا میشود |
pr.number, pr.url | pull requestِ بازِ شاخهی فعلی. نشانِ PR در نوارِ وضعیتِ پایین را آینه میکند. تا وقتی یک PR پیدا نشود، یا وقتی در مخزنِ git نباشی، یا پس از merge یا بستهشدنِ PR، غایب است |
pr.review_state | وضعیتِ بازبینیِ PRِ باز: approved, pending, changes_requested یا draft. ممکن است حتی وقتی pr حاضر است، مستقلاً غایب باشد |
worktree.name | نامِ worktreeِ فعال. فقط در حینِ نشستهای --worktree حاضر است |
worktree.path | مسیرِ مطلقِ پوشهی worktree |
worktree.branch | نامِ شاخهی git برای worktree (مثلاً "worktree-my-feature"). برای worktreeهای مبتنیبرhook غایب است |
worktree.original_cwd | پوشهای که Claude پیش از واردشدن به worktree در آن بود |
worktree.original_branch | شاخهی git که پیش از واردشدن به worktree checkout شده بود. برای worktreeهای مبتنیبرhook غایب است |
اسکیمای کاملِ JSON
دستورِ نوارِ وضعیتت این ساختارِ JSON را از طریقِ stdin دریافت میکند:
{ "cwd": "/current/working/directory", "session_id": "abc123...", "session_name": "my-session", "transcript_path": "/path/to/transcript.jsonl", "model": { "id": "claude-opus-4-8", "display_name": "Opus" }, "workspace": { "current_dir": "/current/working/directory", "project_dir": "/original/project/directory", "added_dirs": [], "git_worktree": "feature-xyz", "repo": { "host": "github.com", "owner": "anthropics", "name": "claude-code" } }, "version": "2.1.90", "output_style": { "name": "default" }, "cost": { "total_cost_usd": 0.01234, "total_duration_ms": 45000, "total_api_duration_ms": 2300, "total_lines_added": 156, "total_lines_removed": 23 }, "context_window": { "total_input_tokens": 15500, "total_output_tokens": 1200, "context_window_size": 200000, "used_percentage": 8, "remaining_percentage": 92, "current_usage": { "input_tokens": 8500, "output_tokens": 1200, "cache_creation_input_tokens": 5000, "cache_read_input_tokens": 2000 } }, "exceeds_200k_tokens": false, "effort": { "level": "high" }, "thinking": { "enabled": true }, "rate_limits": { "five_hour": { "used_percentage": 23.5, "resets_at": 1738425600 }, "seven_day": { "used_percentage": 41.2, "resets_at": 1738857600 } }, "vim": { "mode": "NORMAL" }, "agent": { "name": "security-reviewer" }, "pr": { "number": 1234, "url": "https://github.com/anthropics/claude-code/pull/1234", "review_state": "pending" }, "worktree": { "name": "my-feature", "path": "/path/to/.claude/worktrees/my-feature", "branch": "worktree-my-feature", "original_cwd": "/path/to/project", "original_branch": "main" }}فیلدهایی که ممکن است غایب باشند (در JSON حاضر نباشند):
session_name: فقط وقتی ظاهر میشود که یک نامِ سفارشی با--nameیا/renameتنظیم شده باشدworkspace.git_worktree: فقط وقتی ظاهر میشود که پوشهی فعلی داخلِ یک git worktreeِ پیوندی باشدworkspace.repo: فقط داخلِ یک مخزنِ git با remoteِoriginِ پیکربندیشده ظاهر میشودeffort: فقط وقتی ظاهر میشود که مدلِ فعلی پارامترِ تلاشِ استدلالی را پشتیبانی کندvim: فقط وقتی حالتِ vim فعال باشد ظاهر میشودagent: فقط وقتی با پرچمِ--agentیا با تنظیماتِ ایجنتِ پیکربندیشده اجرا شود ظاهر میشودpr: فقط تا وقتی یک PRِ باز برای شاخهی فعلی پیدا شود ظاهر میشود، و پس از merge یا بستهشدنِ PR حذف میشود.pr.review_stateممکن است مستقلاً غایب باشدworktree: فقط در حینِ نشستهای--worktreeظاهر میشود. وقتی حاضر است،branchوoriginal_branchهم ممکن است برای worktreeهای مبتنیبرhook غایب باشندrate_limits: فقط برای مشترکانِ Claude.ai (Pro/Max) پس از اولین پاسخِ API در نشست ظاهر میشود. هر پنجره (five_hour,seven_day) ممکن است مستقلاً غایب باشد. برای مدیریتِ روانِ غیبت ازjq -r '.rate_limits.five_hour.used_percentage // empty'استفاده کن.
فیلدهایی که ممکن است null باشند:
context_window.current_usage: پیش از اولین فراخوانیِ API در یک نشستnullاست، و دوباره پس از/compactتا وقتی فراخوانیِ API بعدی آن را دوباره پر کندcontext_window.used_percentage,context_window.remaining_percentage: ممکن است اوایلِ نشستnullباشند
فیلدهای ناموجود را با دسترسیِ شرطی و مقادیرِ null را با پیشفرضهای جایگزین در اسکریپتهایت مدیریت کن.
فیلدهای پنجرهی کانتکست
Section titled “فیلدهای پنجرهی کانتکست”شیءِ context_window پنجرهی کانتکستِ زنده را از آخرین پاسخِ API توصیف میکند. از v2.1.132 به بعد، total_input_tokens و total_output_tokens مصرفِ کانتکستِ فعلی را بازتاب میدهند، نه مجموعِ انباشتیِ نشست را.
- مجموعهای ترکیبی (
total_input_tokens,total_output_tokens): توکنهایی که اکنون در پنجرهی کانتکست هستند.total_input_tokensمجموعِinput_tokens،cache_creation_input_tokensوcache_read_input_tokensاست؛total_output_tokensتوکنهای خروجیِ آخرین پاسخ است. هر دو پیش از اولین پاسخِ API برابرِ0اند. - مصرفِ تفکیکی بهازای هر مؤلفه (
current_usage): همان تعدادِ توکنها که بر اساسِ دسته تفکیک شدهاند. این را وقتی استفاده کن که لازم داری hitهای کش را جدا از ورودیِ تازه داشته باشی.
شیءِ current_usage شامل اینهاست:
input_tokens: توکنهای ورودی در کانتکستِ فعلیoutput_tokens: توکنهای خروجیِ تولیدشدهcache_creation_input_tokens: توکنهای نوشتهشده در کشcache_read_input_tokens: توکنهای خواندهشده از کش
برای اینکه فیلدهای کش چه معنایی دارند و چطور محاسبهی هزینه میشوند، بررسیِ کاراییِ کش را ببین.
فیلدِ used_percentage فقط از توکنهای ورودی محاسبه میشود: input_tokens + cache_creation_input_tokens + cache_read_input_tokens. شاملِ output_tokens نمیشود.
اگر درصدِ کانتکست را بهصورتِ دستی از current_usage محاسبه میکنی، از همان فرمولِ فقط-ورودی استفاده کن تا با used_percentage بخواند.
شیءِ current_usage پیش از اولین فراخوانیِ API در یک نشست null است، و دوباره بلافاصله پس از /compact تا وقتی فراخوانیِ API بعدی آن را دوباره پر کند.
نمونهها
Section titled “نمونهها”این نمونهها الگوهای رایجِ نوارِ وضعیت را نشان میدهند. برای استفاده از هر نمونه:
- اسکریپت را در فایلی مثل
~/.claude/statusline.sh(یا.py/.js) ذخیره کن - اجراپذیرش کن:
chmod +x ~/.claude/statusline.sh - مسیر را به تنظیماتت اضافه کن
نمونههای Bash از jq برای تجزیهی JSON استفاده میکنند. Python و Node.js تجزیهی JSON توکار دارند.
مصرفِ پنجرهی کانتکست
Section titled “مصرفِ پنجرهی کانتکست”مدلِ فعلی و مصرفِ پنجرهی کانتکست را با یک نوارِ پیشرفتِ بصری نمایش بده. هر اسکریپت JSON را از stdin میخواند، فیلدِ used_percentage را استخراج میکند، و یک نوارِ ۱۰کاراکتری میسازد که در آن بلوکهای پُر (▓) نشاندهندهی مصرفاند:
#!/bin/bash# Read all of stdin into a variableinput=$(cat)
# Extract fields with jq, "// 0" provides fallback for nullMODEL=$(echo "$input" | jq -r '.model.display_name')PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Build progress bar: printf -v creates a run of spaces, then# ${var// /▓} replaces each space with a block characterBAR_WIDTH=10FILLED=$((PCT * BAR_WIDTH / 100))EMPTY=$((BAR_WIDTH - FILLED))BAR=""[ "$FILLED" -gt 0 ] && printf -v FILL "%${FILLED}s" && BAR="${FILL// /▓}"[ "$EMPTY" -gt 0 ] && printf -v PAD "%${EMPTY}s" && BAR="${BAR}${PAD// /░}"
echo "[$MODEL] $BAR $PCT%"#!/usr/bin/env python3import json, sys
# json.load reads and parses stdin in one stepdata = json.load(sys.stdin)model = data['model']['display_name']# "or 0" handles null valuespct = int(data.get('context_window', {}).get('used_percentage', 0) or 0)
# String multiplication builds the barfilled = pct * 10 // 100bar = '▓' * filled + '░' * (10 - filled)
print(f"[{model}] {bar} {pct}%")#!/usr/bin/env node// Node.js reads stdin asynchronously with eventslet input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name; // Optional chaining (?.) safely handles null fields const pct = Math.floor(data.context_window?.used_percentage || 0);
// String.repeat() builds the bar const filled = Math.floor(pct * 10 / 100); const bar = '▓'.repeat(filled) + '░'.repeat(10 - filled);
console.log(`[${model}] ${bar} ${pct}%`);});وضعیتِ git با رنگها
Section titled “وضعیتِ git با رنگها”شاخهی git را با نشانگرهای رنگیِ فایلهای stageشده و تغییریافته نشان بده. این اسکریپت از کدهای فرارِ ANSI برای رنگهای ترمینال استفاده میکند: \033[32m سبز است، \033[33m زرد، و \033[0m به پیشفرض بازنشانی میکند.
هر اسکریپت بررسی میکند که آیا پوشهی فعلی یک مخزنِ git است، فایلهای stageشده و تغییریافته را میشمارد، و نشانگرهای رنگی نمایش میدهد:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')DIR=$(echo "$input" | jq -r '.workspace.current_dir')
GREEN='\033[32m'YELLOW='\033[33m'RESET='\033[0m'
if git rev-parse --git-dir > /dev/null 2>&1; then BRANCH=$(git branch --show-current 2>/dev/null) STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ') MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
GIT_STATUS="" [ "$STAGED" -gt 0 ] && GIT_STATUS="${GREEN}+${STAGED}${RESET}" [ "$MODIFIED" -gt 0 ] && GIT_STATUS="${GIT_STATUS}${YELLOW}~${MODIFIED}${RESET}"
echo -e "[$MODEL] 📁 ${DIR##*/} | 🌿 $BRANCH $GIT_STATUS"else echo "[$MODEL] 📁 ${DIR##*/}"fi#!/usr/bin/env python3import json, sys, subprocess, os
data = json.load(sys.stdin)model = data['model']['display_name']directory = os.path.basename(data['workspace']['current_dir'])
GREEN, YELLOW, RESET = '\033[32m', '\033[33m', '\033[0m'
try: subprocess.check_output(['git', 'rev-parse', '--git-dir'], stderr=subprocess.DEVNULL) branch = subprocess.check_output(['git', 'branch', '--show-current'], text=True).strip() staged_output = subprocess.check_output(['git', 'diff', '--cached', '--numstat'], text=True).strip() modified_output = subprocess.check_output(['git', 'diff', '--numstat'], text=True).strip() staged = len(staged_output.split('\n')) if staged_output else 0 modified = len(modified_output.split('\n')) if modified_output else 0
git_status = f"{GREEN}+{staged}{RESET}" if staged else "" git_status += f"{YELLOW}~{modified}{RESET}" if modified else ""
print(f"[{model}] 📁 {directory} | 🌿 {branch} {git_status}")except: print(f"[{model}] 📁 {directory}")#!/usr/bin/env nodeconst { execSync } = require('child_process');const path = require('path');
let input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name; const dir = path.basename(data.workspace.current_dir);
const GREEN = '\x1b[32m', YELLOW = '\x1b[33m', RESET = '\x1b[0m';
try { execSync('git rev-parse --git-dir', { stdio: 'ignore' }); const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim(); const staged = execSync('git diff --cached --numstat', { encoding: 'utf8' }).trim().split('\n').filter(Boolean).length; const modified = execSync('git diff --numstat', { encoding: 'utf8' }).trim().split('\n').filter(Boolean).length;
let gitStatus = staged ? `${GREEN}+${staged}${RESET}` : ''; gitStatus += modified ? `${YELLOW}~${modified}${RESET}` : '';
console.log(`[${model}] 📁 ${dir} | 🌿 ${branch} ${gitStatus}`); } catch { console.log(`[${model}] 📁 ${dir}`); }});پیگیریِ هزینه و مدتزمان
Section titled “پیگیریِ هزینه و مدتزمان”هزینههای API و زمانِ سپریشدهی نشستت را دنبال کن. فیلدِ cost.total_cost_usd هزینهی تخمینیِ همهی فراخوانیهای API در نشستِ فعلی را انباشته میکند. فیلدِ cost.total_duration_ms کلِ زمانِ سپریشده از شروعِ نشست را اندازه میگیرد، در حالی که cost.total_api_duration_ms فقط زمانِ صرفشده برای انتظارِ پاسخهای API را دنبال میکند.
هر اسکریپت هزینه را بهصورتِ واحدِ پول قالببندی میکند و میلیثانیه را به دقیقه و ثانیه تبدیل میکند:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
COST_FMT=$(printf '$%.2f' "$COST")DURATION_SEC=$((DURATION_MS / 1000))MINS=$((DURATION_SEC / 60))SECS=$((DURATION_SEC % 60))
echo "[$MODEL] 💰 $COST_FMT | ⏱️ ${MINS}m ${SECS}s"#!/usr/bin/env python3import json, sys
data = json.load(sys.stdin)model = data['model']['display_name']cost = data.get('cost', {}).get('total_cost_usd', 0) or 0duration_ms = data.get('cost', {}).get('total_duration_ms', 0) or 0
duration_sec = duration_ms // 1000mins, secs = duration_sec // 60, duration_sec % 60
print(f"[{model}] 💰 ${cost:.2f} | ⏱️ {mins}m {secs}s")#!/usr/bin/env nodelet input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name; const cost = data.cost?.total_cost_usd || 0; const durationMs = data.cost?.total_duration_ms || 0;
const durationSec = Math.floor(durationMs / 1000); const mins = Math.floor(durationSec / 60); const secs = durationSec % 60;
console.log(`[${model}] 💰 $${cost.toFixed(2)} | ⏱️ ${mins}m ${secs}s`);});نمایشِ چند خط
Section titled “نمایشِ چند خط”اسکریپتت میتواند چند خط خروجی بدهد تا یک نمایشِ غنیتر بسازد. هر دستورِ echo یک ردیفِ جداگانه در ناحیهی وضعیت تولید میکند.
این نمونه چند تکنیک را با هم ترکیب میکند: رنگهای آستانهمحور (سبز زیرِ ۷۰٪، زرد ۷۰ تا ۸۹٪، قرمز ۹۰٪ به بالا)، یک نوارِ پیشرفت، و اطلاعاتِ شاخهی git. هر دستورِ print یا echo یک ردیفِ جداگانه میسازد:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')DIR=$(echo "$input" | jq -r '.workspace.current_dir')COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; RESET='\033[0m'
# Pick bar color based on context usageif [ "$PCT" -ge 90 ]; then BAR_COLOR="$RED"elif [ "$PCT" -ge 70 ]; then BAR_COLOR="$YELLOW"else BAR_COLOR="$GREEN"; fi
FILLED=$((PCT / 10)); EMPTY=$((10 - FILLED))printf -v FILL "%${FILLED}s"; printf -v PAD "%${EMPTY}s"BAR="${FILL// /█}${PAD// /░}"
MINS=$((DURATION_MS / 60000)); SECS=$(((DURATION_MS % 60000) / 1000))
BRANCH=""git rev-parse --git-dir > /dev/null 2>&1 && BRANCH=" | 🌿 $(git branch --show-current 2>/dev/null)"
echo -e "${CYAN}[$MODEL]${RESET} 📁 ${DIR##*/}$BRANCH"COST_FMT=$(printf '$%.2f' "$COST")echo -e "${BAR_COLOR}${BAR}${RESET} ${PCT}% | ${YELLOW}${COST_FMT}${RESET} | ⏱️ ${MINS}m ${SECS}s"#!/usr/bin/env python3import json, sys, subprocess, os
data = json.load(sys.stdin)model = data['model']['display_name']directory = os.path.basename(data['workspace']['current_dir'])cost = data.get('cost', {}).get('total_cost_usd', 0) or 0pct = int(data.get('context_window', {}).get('used_percentage', 0) or 0)duration_ms = data.get('cost', {}).get('total_duration_ms', 0) or 0
CYAN, GREEN, YELLOW, RED, RESET = '\033[36m', '\033[32m', '\033[33m', '\033[31m', '\033[0m'
bar_color = RED if pct >= 90 else YELLOW if pct >= 70 else GREENfilled = pct // 10bar = '█' * filled + '░' * (10 - filled)
mins, secs = duration_ms // 60000, (duration_ms % 60000) // 1000
try: branch = subprocess.check_output(['git', 'branch', '--show-current'], text=True, stderr=subprocess.DEVNULL).strip() branch = f" | 🌿 {branch}" if branch else ""except: branch = ""
print(f"{CYAN}[{model}]{RESET} 📁 {directory}{branch}")print(f"{bar_color}{bar}{RESET} {pct}% | {YELLOW}${cost:.2f}{RESET} | ⏱️ {mins}m {secs}s")#!/usr/bin/env nodeconst { execSync } = require('child_process');const path = require('path');
let input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name; const dir = path.basename(data.workspace.current_dir); const cost = data.cost?.total_cost_usd || 0; const pct = Math.floor(data.context_window?.used_percentage || 0); const durationMs = data.cost?.total_duration_ms || 0;
const CYAN = '\x1b[36m', GREEN = '\x1b[32m', YELLOW = '\x1b[33m', RED = '\x1b[31m', RESET = '\x1b[0m';
const barColor = pct >= 90 ? RED : pct >= 70 ? YELLOW : GREEN; const filled = Math.floor(pct / 10); const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
const mins = Math.floor(durationMs / 60000); const secs = Math.floor((durationMs % 60000) / 1000);
let branch = ''; try { branch = execSync('git branch --show-current', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); branch = branch ? ` | 🌿 ${branch}` : ''; } catch {}
console.log(`${CYAN}[${model}]${RESET} 📁 ${dir}${branch}`); console.log(`${barColor}${bar}${RESET} ${pct}% | ${YELLOW}$${cost.toFixed(2)}${RESET} | ⏱️ ${mins}m ${secs}s`);});لینکهای قابلِ کلیک
Section titled “لینکهای قابلِ کلیک”این نمونه یک لینکِ قابلِ کلیک به مخزنِ GitHubت میسازد. URLِ remoteِ git را میخواند، فرمتِ SSH را با sed به HTTPS تبدیل میکند، و نامِ مخزن را در کدهای فرارِ OSC 8 میپیچد. Cmd (روی macOS) یا Ctrl (روی Windows/Linux) را نگه دار و کلیک کن تا لینک در مرورگرت باز شود.
هر اسکریپت URLِ remoteِ git را میگیرد، فرمتِ SSH را به HTTPS تبدیل میکند، و نامِ مخزن را در کدهای فرارِ OSC 8 میپیچد. نسخهی Bash از printf '%b' استفاده میکند که فرارهای backslash را در شِلهای مختلف مطمئنتر از echo -e تفسیر میکند:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
# Convert git SSH URL to HTTPSREMOTE=$(git remote get-url origin 2>/dev/null | sed 's/git@github.com:/https:\/\/github.com\//' | sed 's/\.git$//')
if [ -n "$REMOTE" ]; then REPO_NAME=$(basename "$REMOTE") # OSC 8 format: \e]8;;URL\a then TEXT then \e]8;;\a # printf %b interprets escape sequences reliably across shells printf '%b' "[$MODEL] 🔗 \e]8;;${REMOTE}\a${REPO_NAME}\e]8;;\a\n"else echo "[$MODEL]"fi#!/usr/bin/env python3import json, sys, subprocess, re, os
data = json.load(sys.stdin)model = data['model']['display_name']
# Get git remote URLtry: remote = subprocess.check_output( ['git', 'remote', 'get-url', 'origin'], stderr=subprocess.DEVNULL, text=True ).strip() # Convert SSH to HTTPS format remote = re.sub(r'^git@github\.com:', 'https://github.com/', remote) remote = re.sub(r'\.git$', '', remote) repo_name = os.path.basename(remote) # OSC 8 escape sequences link = f"\033]8;;{remote}\a{repo_name}\033]8;;\a" print(f"[{model}] 🔗 {link}")except: print(f"[{model}]")#!/usr/bin/env nodeconst { execSync } = require('child_process');const path = require('path');
let input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name;
try { let remote = execSync('git remote get-url origin', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); // Convert SSH to HTTPS format remote = remote.replace(/^git@github\.com:/, 'https://github.com/').replace(/\.git$/, ''); const repoName = path.basename(remote); // OSC 8 escape sequences const link = `\x1b]8;;${remote}\x07${repoName}\x1b]8;;\x07`; console.log(`[${model}] 🔗 ${link}`); } catch { console.log(`[${model}]`); }});مصرفِ محدودیتِ نرخ
Section titled “مصرفِ محدودیتِ نرخ”مصرفِ محدودیتِ نرخِ اشتراکِ Claude.ai را در نوارِ وضعیت نمایش بده. شیءِ rate_limits شاملِ پنجرههای five_hour (پنجرهی غلتانِ ۵ساعته) و seven_day (هفتگی) است. هر پنجره used_percentage (۰ تا ۱۰۰) و resets_at (ثانیههای Unix epoch وقتی پنجره بازنشانی میشود) را فراهم میکند.
این فیلد فقط برای مشترکانِ Claude.ai (Pro/Max) پس از اولین پاسخِ API حاضر است. هر اسکریپت فیلدِ غایب را بهنرمی مدیریت میکند:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')# "// empty" produces no output when rate_limits is absentFIVE_H=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')WEEK=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
LIMITS=""[ -n "$FIVE_H" ] && LIMITS="5h: $(printf '%.0f' "$FIVE_H")%"[ -n "$WEEK" ] && LIMITS="${LIMITS:+$LIMITS }7d: $(printf '%.0f' "$WEEK")%"
[ -n "$LIMITS" ] && echo "[$MODEL] | $LIMITS" || echo "[$MODEL]"#!/usr/bin/env python3import json, sys
data = json.load(sys.stdin)model = data['model']['display_name']
parts = []rate = data.get('rate_limits', {})five_h = rate.get('five_hour', {}).get('used_percentage')week = rate.get('seven_day', {}).get('used_percentage')
if five_h is not None: parts.append(f"5h: {five_h:.0f}%")if week is not None: parts.append(f"7d: {week:.0f}%")
if parts: print(f"[{model}] | {' '.join(parts)}")else: print(f"[{model}]")#!/usr/bin/env nodelet input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name;
const parts = []; const fiveH = data.rate_limits?.five_hour?.used_percentage; const week = data.rate_limits?.seven_day?.used_percentage;
if (fiveH != null) parts.push(`5h: ${Math.round(fiveH)}%`); if (week != null) parts.push(`7d: ${Math.round(week)}%`);
console.log(parts.length ? `[${model}] | ${parts.join(' ')}` : `[${model}]`);});کشکردنِ عملیاتِ پرهزینه
Section titled “کشکردنِ عملیاتِ پرهزینه”اسکریپتِ نوارِ وضعیتت در نشستهای فعال مکرراً اجرا میشود. دستورهایی مثل git status یا git diff میتوانند کند باشند، بهخصوص در مخزنهای بزرگ. این نمونه اطلاعاتِ git را در یک فایلِ موقت کش میکند و فقط هر ۵ ثانیه یکبار تازهاش میکند.
نامِ فایلِ کش باید در طولِ فراخوانیهای نوارِ وضعیت در یک نشست پایدار باشد، اما بین نشستها یکتا باشد تا نشستهای همزمان در مخزنهای مختلف وضعیتِ git کششدهی یکدیگر را نخوانند. شناسههای مبتنیبرفرایند مثل $$، os.getpid() یا process.pid در هر فراخوانی تغییر میکنند و کش را بیاثر میکنند. بهجایش از session_id در ورودیِ JSON استفاده کن: در طولِ عمرِ یک نشست پایدار و بهازای هر نشست یکتاست.
هر اسکریپت پیش از اجرای دستورهای git بررسی میکند که آیا فایلِ کش ناموجود یا قدیمیتر از ۵ ثانیه است:
#!/bin/bashinput=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')DIR=$(echo "$input" | jq -r '.workspace.current_dir')SESSION_ID=$(echo "$input" | jq -r '.session_id')
CACHE_FILE="/tmp/statusline-git-cache-$SESSION_ID"CACHE_MAX_AGE=5 # seconds
cache_is_stale() { [ ! -f "$CACHE_FILE" ] || \ # stat -f %m is macOS, stat -c %Y is Linux [ $(($(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -gt $CACHE_MAX_AGE ]}
if cache_is_stale; then if git rev-parse --git-dir > /dev/null 2>&1; then BRANCH=$(git branch --show-current 2>/dev/null) STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ') MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ') echo "$BRANCH|$STAGED|$MODIFIED" > "$CACHE_FILE" else echo "||" > "$CACHE_FILE" fifi
IFS='|' read -r BRANCH STAGED MODIFIED < "$CACHE_FILE"
if [ -n "$BRANCH" ]; then echo "[$MODEL] 📁 ${DIR##*/} | 🌿 $BRANCH +$STAGED ~$MODIFIED"else echo "[$MODEL] 📁 ${DIR##*/}"fi#!/usr/bin/env python3import json, sys, subprocess, os, time
data = json.load(sys.stdin)model = data['model']['display_name']directory = os.path.basename(data['workspace']['current_dir'])session_id = data['session_id']
CACHE_FILE = f"/tmp/statusline-git-cache-{session_id}"CACHE_MAX_AGE = 5 # seconds
def cache_is_stale(): if not os.path.exists(CACHE_FILE): return True return time.time() - os.path.getmtime(CACHE_FILE) > CACHE_MAX_AGE
if cache_is_stale(): try: subprocess.check_output(['git', 'rev-parse', '--git-dir'], stderr=subprocess.DEVNULL) branch = subprocess.check_output(['git', 'branch', '--show-current'], text=True).strip() staged = subprocess.check_output(['git', 'diff', '--cached', '--numstat'], text=True).strip() modified = subprocess.check_output(['git', 'diff', '--numstat'], text=True).strip() staged_count = len(staged.split('\n')) if staged else 0 modified_count = len(modified.split('\n')) if modified else 0 with open(CACHE_FILE, 'w') as f: f.write(f"{branch}|{staged_count}|{modified_count}") except: with open(CACHE_FILE, 'w') as f: f.write("||")
with open(CACHE_FILE) as f: branch, staged, modified = f.read().strip().split('|')
if branch: print(f"[{model}] 📁 {directory} | 🌿 {branch} +{staged} ~{modified}")else: print(f"[{model}] 📁 {directory}")#!/usr/bin/env nodeconst { execSync } = require('child_process');const fs = require('fs');const path = require('path');
let input = '';process.stdin.on('data', chunk => input += chunk);process.stdin.on('end', () => { const data = JSON.parse(input); const model = data.model.display_name; const dir = path.basename(data.workspace.current_dir); const sessionId = data.session_id;
const CACHE_FILE = `/tmp/statusline-git-cache-${sessionId}`; const CACHE_MAX_AGE = 5; // seconds
const cacheIsStale = () => { if (!fs.existsSync(CACHE_FILE)) return true; return (Date.now() / 1000) - fs.statSync(CACHE_FILE).mtimeMs / 1000 > CACHE_MAX_AGE; };
if (cacheIsStale()) { try { execSync('git rev-parse --git-dir', { stdio: 'ignore' }); const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim(); const staged = execSync('git diff --cached --numstat', { encoding: 'utf8' }).trim().split('\n').filter(Boolean).length; const modified = execSync('git diff --numstat', { encoding: 'utf8' }).trim().split('\n').filter(Boolean).length; fs.writeFileSync(CACHE_FILE, `${branch}|${staged}|${modified}`); } catch { fs.writeFileSync(CACHE_FILE, '||'); } }
const [branch, staged, modified] = fs.readFileSync(CACHE_FILE, 'utf8').trim().split('|');
if (branch) { console.log(`[${model}] 📁 ${dir} | 🌿 ${branch} +${staged} ~${modified}`); } else { console.log(`[${model}] 📁 ${dir}`); }});پیکربندیِ Windows
Section titled “پیکربندیِ Windows”روی Windows، Claude Code دستورهای نوارِ وضعیت را وقتی Git Bash نصب باشد از طریقِ Git Bash اجرا میکند، یا وقتی Git Bash نباشد از طریقِ PowerShell.
Git Bash بکاسلشهای بدونِ کوتیشن را بهعنوانِ کاراکترهای فرار تلقی میکند، پس مسیری به سبکِ Windows مثل C:\Users\username\script.mjs با جداکنندههای حذفشده به اجراکنندهی اسکریپت میرسد و دستور بدونِ خطای نمایان شکست میخورد. مسیرهای فایل را در رشتهی command با اسلشِ رو به جلو بنویس، همانطور که در نمونههای زیر نشان داده شده. کوتاهنوشتِ ~ هم کار میکند و به پوشهی خانگیِ Windowsت گسترش مییابد.
برای اجرای یک اسکریپتِ PowerShell بهعنوانِ نوارِ وضعیتت، آن را از طریقِ powershell فراخوانی کن. این چه Claude Code دستور را از طریقِ Git Bash مسیریابی کند و چه از طریقِ PowerShell، کار میکند:
{ "statusLine": { "type": "command", "command": "powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1" }}$input_json = $input | Out-String | ConvertFrom-Json$cwd = $input_json.cwd$model = $input_json.model.display_name$used = $input_json.context_window.used_percentage$dirname = Split-Path $cwd -Leaf
if ($used) { Write-Host "$dirname [$model] ctx: $used%"} else { Write-Host "$dirname [$model]"}یا، وقتی Git Bash نصب باشد، یک اسکریپتِ Bash را مستقیم اجرا کن:
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh" }}#!/usr/bin/env bashinput=$(cat)cwd=$(echo "$input" | grep -o '"cwd":"[^"]*"' | cut -d'"' -f4)model=$(echo "$input" | grep -o '"display_name":"[^"]*"' | cut -d'"' -f4)dirname="${cwd##*[/\\]}"echo "$dirname [$model]"نوارهای وضعیتِ سابایجنت
Section titled “نوارهای وضعیتِ سابایجنت”تنظیمِ subagentStatusLine بدنهی یک ردیفِ سفارشی را برای هر سابایجنت که در پنلِ ایجنت زیرِ پرامپت نشان داده میشود رندر میکند. از آن استفاده کن تا ردیفِ پیشفرضِ name · description · token count را با قالببندیِ خودت جایگزین کنی.
{ "subagentStatusLine": { "type": "command", "command": "~/.claude/subagent-statusline.sh" }}این دستور یکبار در هر تیکِ تازهسازی اجرا میشود، با همهی ردیفهای سابایجنتِ قابلِمشاهده که بهصورتِ یک شیءِ JSON واحد روی stdin منتقل میشوند. ورودی شاملِ فیلدهای پایهی hook بهعلاوهی columns (عرضِ قابلِاستفادهی ردیف) و یک آرایهی tasks است، که در آن هر task اینها را دارد: id، name، type، status، description، label، startTime، tokenCount، tokenSamples و cwd.
برای هر ردیفی که میخواهی بازنویسی کنی، یک خطِ JSON روی stdout بنویس، به شکلِ {"id": "<task id>", "content": "<row body>"}. رشتهی content همانطور که هست رندر میشود، از جمله رنگهای ANSI و hyperlinkهای OSC 8. idِ یک task را حذف کن تا رندرِ پیشفرضِ آن ردیف حفظ شود؛ یک رشتهی contentِ خالی منتشر کن تا آن را پنهان کنی.
همان دروازههای اعتماد (trust) و disableAllHooks که برای statusLine اعمال میشوند، اینجا هم اعمال میشوند. پلاگینها میتوانند یک subagentStatusLineِ پیشفرض را در settings.jsonِ خودشان عرضه کنند.
نکتهها
Section titled “نکتهها”- با ورودیِ ساختگی تست کن:
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/home/user/project"},"context_window":{"used_percentage":25},"session_id":"test-session-abc"}' | ./statusline.sh - خروجی را کوتاه نگه دار: نوارِ وضعیت عرضِ محدودی دارد، پس خروجیِ طولانی ممکن است بریده شود یا بهشکلِ ناجوری شکسته شود
- عملیاتِ کند را کش کن: اسکریپتت در نشستهای فعال مکرراً اجرا میشود، پس دستورهایی مثل
git statusمیتوانند باعثِ کندی شوند. برای مدیریتِ این موضوع، نمونهی کشکردن را ببین.
پروژههای جامعهای مثل ccstatusline و starship-claude پیکربندیهای ازپیشساخته با تمها و قابلیتهای بیشتر فراهم میکنند.
عیبیابی
Section titled “عیبیابی”نوارِ وضعیت ظاهر نمیشود
- بررسی کن که اسکریپتت اجراپذیر است:
chmod +x ~/.claude/statusline.sh - بررسی کن که اسکریپتت روی stdout خروجی میدهد، نه stderr
- اسکریپتت را بهصورتِ دستی اجرا کن تا مطمئن شوی خروجی تولید میکند
- روی Windows با Git Bashِ نصبشده، بکاسلشهای مسیرِ
commandاحتمالاً پیش از اجرای اسکریپت بهعنوانِ کاراکترهای فرار مصرف میشوند. در مسیر از اسلشِ رو به جلو استفاده کن. پیکربندیِ Windows را ببین. - اگر
disableAllHooksدر تنظیماتت رویtrueباشد، نوارِ وضعیت هم غیرفعال میشود. این تنظیم را حذف کن یا رویfalseبگذار تا دوباره فعال شود. claude --debugرا اجرا کن تا کدِ خروج و stderrِ اولین فراخوانیِ نوارِ وضعیت در یک نشست لاگ شود- از Claude بخواه فایلِ تنظیماتت را بخواند و دستورِ
statusLineرا مستقیم اجرا کند تا خطاها رو بیاید
نوارِ وضعیت -- یا مقادیرِ خالی نشان میدهد
- فیلدها ممکن است پیش از تکمیلِ اولین پاسخِ API برابرِ
nullباشند - مقادیرِ null را در اسکریپتت با جایگزینهایی مثل
// 0در jq مدیریت کن - اگر مقادیر پس از چند پیام همچنان خالی ماندند، Claude Code را دوباره راهاندازی کن
درصدِ کانتکست مقادیرِ غیرمنتظره نشان میدهد
- برای سادهترین وضعیتِ دقیقِ کانتکست از
used_percentageاستفاده کن - درصدِ کانتکست ممکن است بهخاطرِ زمانِ محاسبهی هر کدام، با خروجیِ
/contextفرق کند
لینکهای OSC 8 قابلِ کلیک نیستند
-
بررسی کن که ترمینالت از hyperlinkهای OSC 8 پشتیبانی میکند (iTerm2، Kitty، WezTerm)
-
Terminal.app از لینکهای قابلِ کلیک پشتیبانی نمیکند
-
اگر متنِ لینک ظاهر میشود ولی قابلِ کلیک نیست، شاید Claude Code پشتیبانی از hyperlink را در ترمینالت تشخیص نداده باشد. این معمولاً Windows Terminal و سایرِ شبیهسازهایی که در فهرستِ تشخیصِ خودکار نیستند را درگیر میکند. متغیرِ محیطیِ
FORCE_HYPERLINKرا تنظیم کن تا پیش از راهاندازیِ Claude Code تشخیص را بازنویسی کند:Terminal window FORCE_HYPERLINK=1 claudeدر PowerShell، ابتدا متغیر را در نشستِ فعلی تنظیم کن:
Terminal window $env:FORCE_HYPERLINK = "1"; claude -
نشستهای SSH و tmux ممکن است بسته به پیکربندی توالیهای OSC را حذف کنند
-
اگر توالیهای فرار بهصورتِ متنِ خام مثل
\e]8;;ظاهر میشوند، برای مدیریتِ مطمئنترِ فرار بهجایecho -eازprintf '%b'استفاده کن
خرابیِ نمایش با توالیهای فرار
- توالیهای فرارِ پیچیده (رنگهای ANSI، لینکهای OSC 8) گاهی میتوانند اگر با سایرِ بهروزرسانیهای رابطِ کاربری همپوشانی پیدا کنند، باعثِ خروجیِ درهم شوند
- اگر متنِ خراب دیدی، اسکریپتت را به خروجیِ متنِ ساده سادهسازی کن
- نوارهای وضعیتِ چندخطی با کدهای فرار بیشتر از متنِ سادهٔ تکخطی در معرضِ مشکلاتِ رندر هستند
اعتماد به فضای کاری لازم است
- دستورِ نوارِ وضعیت فقط در صورتی اجرا میشود که پنجرهی اعتماد به فضای کاری (workspace trust) را برای پوشهی فعلی پذیرفته باشی. چون
statusLineیک دستورِ شِل اجرا میکند، به همان پذیرشِ اعتمادی نیاز دارد که hookها و سایرِ تنظیماتِ اجراکنندهی شِل لازم دارند. - اگر اعتماد پذیرفته نشده باشد، بهجای خروجیِ نوارِ وضعیتت اعلانِ
statusline skipped · restart to fixرا میبینی. Claude Code را دوباره راهاندازی کن و پرامپتِ اعتماد را بپذیر تا فعال شود.
خطا یا گیرکردنِ اسکریپت
- اسکریپتهایی که با کدِ غیرصفر خارج میشوند یا خروجی تولید نمیکنند باعثِ خالیشدنِ نوارِ وضعیت میشوند
- اسکریپتهای کند تا وقتی کامل شوند بهروزرسانیِ نوارِ وضعیت را مسدود میکنند. اسکریپتها را سریع نگه دار تا از خروجیِ کهنه جلوگیری شود.
- اگر در حینِ اجرای یک اسکریپتِ کند یک بهروزرسانیِ جدید رخ بدهد، اسکریپتِ در جریان لغو میشود
- اسکریپتت را پیش از پیکربندی، مستقلاً با ورودیِ ساختگی تست کن
اعلانها ردیفِ نوارِ وضعیت را به اشتراک میگذارند
- اعلانهای سیستمی مثل خطاهای سرورِ MCP و بهروزرسانیهای خودکار در سمتِ راستِ همان ردیفِ نوارِ وضعیتت نمایش داده میشوند. اعلانهای گذرا مثل هشدارِ کمبودنِ کانتکست هم در همین ناحیه گردش میکنند.
- فعالکردنِ حالتِ verbose یک شمارندهی توکن به این ناحیه اضافه میکند
- روی ترمینالهای باریک، این اعلانها ممکن است خروجیِ نوارِ وضعیتت را ببُرند