תיעוד 49
שורת מצב
שורה אופציונלית בתחתית ה-pager, מעל סרגל קיצורי המקשים במסך מלא, מתחת לשורת המידע של ה-prompt במצב מינימלי, ומנוטרלת כברירת מחדל. היא מציגה הקשר הפעלה חי, כגון הדגם, ניצול חלון ההקשר, עלות, ספרייה ו-worktree של git, או את הפלט של כל סקריפט שתגדיר. מצטרפים באמצעות [ui.status_line] ב-~/.grok/config.toml.
#הגדרה
#מובנה
[ui.status_line]
type = "builtin"
items = ["cwd", "model", "context"]
# default when omittedזה מוצג, לדוגמה, כ-grok-shell-status-line │ Grok 4.5 │ 12% ctx. פריטים מופיעים בסדר שבו ציינת אותם, ופריטים ארוכים מקוצרים באמצעות …: הספרייה ושם ההפעלה ב-40 עמודות, הדגם ב-30.
| פריט | מציג |
|---|---|
cwd | ספרייה נוכחית (basename) |
model | שם תצוגה של הדגם |
context | אחוז מחלון ההקשר, בצבע ענבר בסף הדחיסה האוטומטית (auto-compaction) או ב-80% כשהסוכן אינו מדווח על סף כזה |
cost | עלות ההפעלה, מוסתרת מתחת ל-$0.005 כדי שלעולם לא תוצג עלות מטעה של $0.00 |
turn-timer | הזמן שחלף בתור שרץ, החל משנייה אחת ואילך |
session-name | שם ההפעלה, כאשר הוא מוגדר |
#פקודה
כוון את command לסקריפט. Grok מזרים JSON אליו ב-stdin ומציג את ה-stdout שלו. קידומת ~/ נפתחת לספריית הבית שלך.
[ui.status_line]
type = "command"
command = "~/.grok/statusline.sh"שמות השדות והקינון שלהם עוקבים אחר המוסכמה הנפוצה של שורת מצב, כך שסקריפט מוסב דורש בדרך כלל עריכה קטנה ולא שכתוב מלא. כל מה שאינו מופיע בטבלה להלן אינו נשלח.
#מנוטרל
הערך type = "disabled", שהוא ברירת המחדל, אינו מציג דבר; הערכים off, none ו-hidden מתקבלים כאיותים נרדפים של disabled.
#אפשרויות
| מפתח | סוג | ברירת מחדל | תיאור |
|---|---|---|---|
type | string | disabled | builtin, command, או disabled. |
items | array | ["cwd", "model", "context"] | מקטעים מובנים, לפי הסדר. |
command | string | ללא | סקריפט עבור type = "command". |
padding | integer | 0 | ריווח אופקי, בתווים לכל צד, מוגבל ל-16 לכל היותר. ריווח רחב מספיק שלא משאיר עמודות שומר את מקום השורה אך אינו מציג בה דבר. |
refresh_interval | integer | לא מוגדר | שורות command בלבד, בשניות, מ-1 עד 86,400. מריץ מחדש את הסקריפט בתדירות זו גם כאשר שום דבר לא השתנה, כך שהפעלה ללא פעילות יכולה עדיין להציג שינוי: קריאת תקלה, סטטוס CI. כאשר אינו מוגדר, השורה נשארת מונעת מאירועים בלבד. הריצה המתוזמנת נושאת את הערך "trigger": "refresh_interval", וכשלים שלה שומרים על הפלט האחרון במקום לצייר שגיאה (ראה הפעלות רענון). סקריפט שפונה לרשת צריך להעדיף מרווח זמן ארוך יותר ולקרוא ממטמון בריצות של state. |
#כיצד זה עובד
- רענון. השורה מתעדכנת כאשר מצב ההפעלה משתנה (תחילת הפעלה, סיום תור, החלפת דגם או רמת מאמץ, הזזת
HEAD, דחיסה, התחברות לקוח) ובאופן רציף בזמן שתור רץ, ולא לפי טיימר. הפעלה ללא פעילות אינה מריצה מחדש את הסקריפט שלך, ולכן שעון בתוכו לא יתקתק מעצמו, אלא אם תגדיר אתrefresh_interval, שמוסיף טיימר מעל לכל האמור לעיל. עדכונים אלה מושהים (debounce) בפרק זמן קבוע של 300 מילישניות, כך שתור עמוס אינו יכול להריץ את הסקריפט שלך בכל פריים. שינוי שחייב להופיע מיד (שינוי גודל, תצלום מצב חדש, החלפת סוכנים) ממתין 100 מילישניות בלבד. ריצה שכבר מתבצעת לעולם אינה מבוטלת: השינוי הבא ממתין לסיומה. Grok קורא את[ui.status_line]בעת ההפעלה, ולכן שינויים בו נכנסים לתוקף בהפעלה הבאה. - פלט. כל שורה שאתה מדפיס הופכת לשורה אחת של שורת המצב, עד חמש שורות, וכל שורה נחתכת ב-1024 תווים, כולל רצפי המילוט של ANSI עצמם, כך שלשורה עתירת צבעים יש פחות מקום לטקסט. מסוף נמוך מכיל פחות שורות, ומשמיט את העודף מלמטה. צבעי ANSI נתמכים; כל רצף מילוט אחר (תנועת סמן, מחיקת שורה, דריסה באמצעות מעבר לתחילת שורה) מושמט. קישורי OSC 8 נתמכים עבור יעדי
http,httpsו-mailto, וכל יעד אחר מוצג כטקסט רגיל. פלטstdoutמעבר ל-64 KiB נקטם והסקריפט נעצר. סקריפט שמצליח ואינו מדפיס דבר מעלים את השורה במקום לחזור למקטעים המובנים, ולכן סקריפט שמדפיס רק לעיתים מזיז את התמליל בשורה אחת כשהוא מופיע ונעלם. - הגדרת גודל. Grok מגדיר את
COLUMNSואתLINESלגודל השורה שהפלט שלך ממלא, ולא לגודל החלון: הריווח של החלונית וה-paddingשלך כבר מנוכים. הפקודהtputמדווחת עליהם גם כן, כיוון שהיא קוראת אותם כאשרstdoutאינו מסוף. המשתנהLINESהוא הגודל שהשורה ממלאת כרגע ולא הגודל שאליו היא עשויה לגדול, ולכן הערך שלו הוא1עד שתדפיס יותר; התקרה היא חמש שורות ללא קשר לערך המצוין. לפני שהשורה צוירה פעם אחת, ובפריים שאין בו מקום עבורה, הגודל הוא הגודל האחרון שבו השורה צוירה, או 80x1 אם היא מעולם לא צוירה. - מעטפת (Shell). הערך
commandהוא שורת פקודה של מעטפת, כך ש-jq -r '…'וצינורות (pipes) עובדים כפי שנכתבו. נתיב מורץ ישירות כאשר הוא מציין קובץ בר-ביצוע, ובאמצעותsh -cבכל מקרה אחר, שזה מה שמריץ סקריפט ששורת ה-#!שלו חסרה או שגויה. הקף במירכאות נתיב המכיל רווחים כפי שהיית עושה בשורת פקודה. כל ריצה היא תהליך חדש, כך שעריכה של קובץ הסקריפט חלה בריצה הבאה. - עבודה ברקע אינה שורדת. כל מה שסקריפט משאיר פועל מחוסל כאשר הריצה מסתיימת, בכל תרחיש: יציאה תקינה, חריגה מזמן ההמתנה (timeout), או פלט רב מדי. הריצה מסתיימת כשהסקריפט שלך יוצא, ולכן כל מה שתהליך רקע מדפיס לאחר מכן אובד.
- סביבה. סקריפטים רצים בספריית העבודה של ההפעלה, לאחר מכן בשורש המאגר, ולאחר מכן בספרייה של ה-
pagerעצמו, לפי מה שהוא נתיב מקומי ראשון, עם מגבלת זמן של 10 שניות, שלאחריה השורה מציגה[status line: timed out]. המשתניםCOLUMNSו-LINESמתארים את השורה שהסקריפט ממלא, לא את החלון. קובציrcשל מעטפת אינם רצים (BASH_ENVו-ENVמנוקים), ומוגדרGIT_OPTIONAL_LOCKS=0. כליpagerועורכי טקסט מנוטרלים באותו אופן שבו שאר חלקי Grok מנטרלים אותם, כך שקריאה ל-gitאו ל-ghבתוך הסקריפט שלך לא תיחסם בהמתנה לאחד מהם. - קלט. מטען ה-JSON נכתב ל-
stdinעם שורה חדשה בסופו, כך שגםread -r lineוגםinput=$(cat)עובדים.
#הפעלות רענון
הגדר את refresh_interval בשורת command והסקריפט ירוץ מחדש גם לפי טיימר, כך שהודעת תקלה או סטטוס CI יוכלו להגיע לשורה בזמן שההפעלה במצב סרק:
[ui.status_line]
type = "command"
command = "~/.grok/statusline.sh"
refresh_interval = 300
# seconds- המטען מציין מדוע הסקריפט רץ. ריצה שעונה לטיימר נושאת את הערך
"trigger": "refresh_interval", כאשר שינוי מצב שמגיע בזמן שמועדת הפעלת טיימר מצטרף לאותה ריצה, וריצה ללא הפעלת טיימר נושאת את הערך"trigger": "state". פנה לרשת ב-refresh_intervalוקרא ממטמון ב-state, אחרת תור עמוס, שמריץ את הסקריפט מחדש ברציפות, יהפוך לסערת בקשות כנגד השירות שהסקריפט קורא לו. - המטען הוא האחרון ש-Grok שלח. ריצת טיימר מריצה מחדש את הסקריפט שלך עם המטען משינוי המצב האחרון, כך שמספרי ההפעלה שלו: עלות, הקשר, אסימונים, נכונים לאותו שינוי, ולא למועד הפעלת הטיימר. רק מה שהסקריפט שלך מביא בעצמו הוא עדכני.
- כשלי רענון שומרים על הפלט האחרון. ברגע שהסקריפט שלך ענה, הדפיס שורה, או בכוונה לא הדפיס דבר, ריצת טיימר שנכשלת או חורגת מזמן ההמתנה משאירה את השורה בדיוק כפי שהייתה, בין אם זה הפלט האחרון ובין אם זה כשל שריצת מצב כבר ציירה, וכותבת את הכשל אל
~/.grok/logs/unified.jsonl, כך שנקודת קצה לא יציבה לא תציג שגיאה לאורך לילה שקט. שלושה כשלי רענון רצופים מעידים שהסקריפט עצמו שבור, והשגיאה מוצגת בכל זאת; כשל רענון לפני שהסקריפט ענה על משהו, בהפעלה חדשה, או מיד לאחר החלפת סוכנים, מוצג גם כן מיד, כיוון שאין מה לשמור. ריצה המופעלת על ידי מצב הפעלה עדיין מדווחת על הכשל שלה מיד, כתמיד. - הפעלות שהוחמצו מתמזגות. בזמן שהשורה מוסתרת (תצוגת סוכן משנה במסך מלא, מסך הפתיחה) או כאשר ריצה כבר תופסת את המשבצת, ההפעלה ממתינה ולשורה מגיעה ריצה אחת כאשר הדבר מתאפשר, לעולם לא פרץ של הפעלות עבור אלו שהושעו או דולגו במהלך תור ארוך. הטיימר שומר על הקצב שלו ללא קשר לזמן הריצה של הסקריפט שלך: הפעלה שמגיע זמנה בזמן שריצה עדיין מתבצעת מועברת לריצה הבאה במקום להצטבר מאחוריה.
- הטיימר שייך למצב שמריץ סקריפט. הערך
refresh_intervalתחתbuiltinאינו מתזמן דבר ומדווח באמצעותgrok inspect; תחתdisabledהוא כבוי יחד עם כל השאר.
#נתונים זמינים
בעת הסבת סקריפט, קרא שדות אלה בעיון. workspace.repo_root הוא שורש המאגר, ואין project_dir, שם המשמש במקומות אחרים עבור ספריית הפעלה. המשתנה context_window.session_usage וספירות האסימונים של session_* הם מצטברים עבור כל ההפעלה, ולא עבור קריאה בודדת, בעוד שהחלון החי הוא context_window.context_tokens. אין רשימה של ספריות הפעלה נוספות, מכיוון של-Grok אין כאלה. transcript_path מציין את זרם העדכונים של Grok עצמו ולא תמליל בפורמט של כלי אחר, ו-prompt_id קיים רק בזמן שתור רץ. בכל אחד מהמקרים, סקריפט מוסב קורא ערך ריק ולא תשובה שגויה, לכן הגן על השדות שבהם אתה משתמש.
שום דבר מחוץ לטבלה להלן אינו נשלח. סקריפט מוסב שקורא ספירת שורות שהסוכן שינה, סיכום מגבלת קצב (rate-limit), מצב עורך, דגל חשיבה (thinking) או מצב מהיר (fast-mode), סגנון פלט, בקשת משיכה (pull request), ספריות הפעלה נוספות, או את הספרייה שממנה נוצר ה-worktree, יגלה שהם חסרים: כל אחד מהם הוא תכונה שאין ל-Grok או מספר שאינו יכול לספק באופן מהימן.
| שדה | תיאור |
|---|---|
cwd, session_id | ספריית עבודה ומזהה הפעלה ייחודי |
session_name | שם הלשונית של ההפעלה, ממולא על ידי הלקוח. קיים ב-stdin של command, חסר בהודעת SessionStatus |
prompt_id | מזהה UUID של ה-prompt המעובד. קיים רק במהלך תור |
transcript_path | נתיב לקובץ updates.jsonl של ההפעלה. הקובץ הוא זרם העדכונים של Grok עצמו, כך שסקריפט המפענח פורמט תמליל של כלי אחר לא יקרא אותו |
model.id, model.display_name | מזהה דגם ושם תצוגה. מושמט כאשר הסוכן אינו יכול לקרוא את הדגם של ההפעלה |
workspace.current_dir | ספרייה נוכחית |
workspace.repo_root | שורש המאגר, חסר מחוץ למאגר. אינו project_dir, שם המשמש במקומות אחרים עבור ספריית הפעלה |
workspace.branch | הענף שנבדק (checked-out), בכל מאגר. חסר במצב detached HEAD |
workspace.git_worktree | שם ה-worktree, בתוך worktree מקושר |
workspace.repo.{host,owner,name} | מפוענח מתוך ה-remote בשם origin, בתוך מאגר git. owner מושמט עבור remote ללא מקטע בעלים |
schema_version | מהדורת מבנה המטען. הוספת שדה לעולם אינה מקדמת אותה; הסרה או שינוי טיפוס מקדמים אותה. בדוק אותה באמצעות >=, ובצע הסתעפות קוד לפיה ולא לפי version |
version | גרסת שחרור של Grok, לתצוגה |
cost.total_duration_ms | מילישניות מאז שתהליך זה התחבר להפעלה. הפעלה שחודשה נספרת מהחידוש, כפי שנספרת העלות שלה |
cost.total_cost_usd, cost.total_api_duration_ms | עלות ההפעלה ומילישניות של המתנה ל-API. העלות חסרה עד שלמשהו בהפעלה יש מחיר, וגם כאשר ספר החשבונות של השימוש אינו קריא, לכן התייחס לעלות חסרה כאל ערך לא ידוע ולא כאל אפס |
context_window.context_window_size | גודל חלון הקשר מרבי, באסימונים. מושמט עד שחלון הדגם ידוע |
context_window.context_tokens | אסימונים שהשיחה תופסת כרגע, בספירת קלט בלבד, כך שהערך יורד לאחר דחיסה (compaction). מושמט כאשר הסוכן אינו יכול לקרוא את הספירה, כך ש-0 תמיד מציין חלון הקשר ריק |
context_window.session_input_tokens, .session_output_tokens | מחויבים לאורך כל ההפעלה, כך שהם רק גדלים. נקראים על שם ההפעלה מכיוון שזה מה שהם סופרים: total_* משמש במקומות אחרים עבור מה שנמצא בחלון כרגע, שכאן הוא context_tokens. חלוקה שלהם ב-context_window_size עוברת את 100% וממשיכה לעלות. מושמטים כאשר ספר החשבונות של השימוש אינו קריא |
context_window.used_percentage, .remaining_percentage | עד כמה החלון מלא כרגע, מספרים שלמים מ-0 עד 100. מושמטים יחד עם context_window_size או context_tokens, שכן אחוז מחלון לא ידוע אינו מספר |
context_window.session_usage.{input_tokens,output_tokens,cache_creation_input_tokens,cache_read_input_tokens} | input_tokens, cache_creation_input_tokens ו-cache_read_input_tokens, שסכומם שווה ל-session_input_tokens, בתוספת output_tokens. מצטבר עבור כל ההפעלה, לא עבור תור בודד. חסר לפני הקריאה הראשונה |
context_window.auto_compact_threshold_percent | הסף שבו ההפעלה מבצעת דחיסה אוטומטית. מושמט כאשר הסוכן לא דיווח על סף |
effort.level | רמת מאמץ הסקת מסקנות (reasoning effort), כאשר הדגם תומך בכך |
turn.started_at_ms | מילישניות יוניקס שבהן התחיל התור שרץ, חסר בין תורים. החסר זאת מהשעון שלך כדי לחשב את הזמן שחלף |
worktree.{name,path,branch,main_worktree_root} | ה-worktree הפעיל, בתוך worktree מקושר. name מושמט עבור worktree בשורש מערכת הקבצים, ו-main_worktree_root הוא המקום שממנו ה-worktree התפצל |
trigger | הסיבה להפעלת ריצה זו: refresh_interval עבור ריצה שהטיימר ביקש, state בכל מקרה אחר. קיים ב-stdin של שורת פקודה, חסר בהודעת SessionStatus, המתארת את ההפעלה ולא ריצה מסוימת |
שדות ש-Grok אינו יכול לספק מושמטים במקום להישלח כשומרי מקום, כך שהשורה לעולם אינה מציגה ערך מומצא. הגן עליהם תמיד: jq -r מדפיס את הטקסט המילולי null עבור מפתח חסר, לכן כתוב // 0 או // "?" ב-jq, ו-?. ב-JavaScript.
#דוגמה
שמור סקריפט (לדוגמה ~/.grok/statusline.sh), הפוך אותו לקובץ בר-ביצוע באמצעות chmod +x, והגדר אותו כ-command. דוגמה זו משתמשת ב-jq. Python ו-Node.js מפענחות JSON באופן טבעי. המטען אינו נושא ספירת קבצים שהשתנו, לכן הסקריפט קורא ל-git עבור נתון זה.
#!/bin/bash
input=$(cat)
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
MODEL=$(echo "$input" | jq -r '.model.display_name // "?"')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
BRANCH=$(echo "$input" | jq -r '.workspace.branch // "detached"')
DIRTY=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
printf '%b\n' "${DIR##*/} │ $MODEL │ ${PCT}% ctx │ \033[32m$BRANCH\033[0m ~$DIRTY"#טיפים
- בדוק באמצעות קלט דמה:
echo '{"session_id":"t","workspace":{"current_dir":"/tmp/demo"},"model":{"display_name":"Grok 4.5"},"context_window":{"used_percentage":25}}' | ./statusline.sh - שמור במטמון פקודות איטיות כגון
git statusלקובץ זמני שמפתח החיפוש שלו מבוסס עלsession_id, ורענן אותו כל כמה שניות. המזההsession_idיציב לאורך כל ההפעלה וייחודי בין הפעלות שונות. - השתמש ב-
printf '%b'במקום ב-echo -eעבור רצפי מילוט אמינים.
#פתרון בעיות
- שום דבר לא מוצג. Grok קורא את
[ui.status_line]בעת ההפעלה, לכן הפעל אותו מחדש לאחר עריכתconfig.toml. הפעלה מחדש מספיקה: כאשר הלקוח החדש מתחבר, הסוכן מפעיל את השורה עבור הפעלה שעדיין רצה. השורה מוצגת רק כאשר תצוגת הסוכן פעילה, כלומר לא במסך הפתיחה ולא כאשר תצוגת סוכן משנה פתוחה במסך מלא. ודא שהערךtypeאינוdisabled, ושסקריפט פקודה הוא בר-ביצוע וכותב ל-stdout. - הודעה בשורה. שורה המתחילה ב-
[ui.status_line]מציינת ש-Grok לא הצליח להשתמש בסעיף זה כפי שנכתב: היא מציינת את המפתח שהוא לא הצליח לקרוא, או מציינת מה המצב שבחרת עדיין דורש. הפקודהgrok inspectמציגה את אותן הבעיות, כולל מפתחות שגרסה זו אינה מכירה, וזה המקום לחפש בו כאשר השורה כבויה. כל מה שהוא הצליח לקרוא עדיין חל, ו-Grok משאיר את הסעיף כפי שכתבת אותו במקום לשכתב סעיף שאינו יכול לקרוא. הגדרתtype = "disabled"מסירה את השורה ואת ההודעה. - שורה ריקה שלעולם אינה מתמלאת. הסוכן אינו שולח עדכוני מצב, מה שבדרך כלל מעיד על תהליך
grokאו תהליךleaderישן יותר מלקוח זה. הפעל מחדש את ה-leaderאו עדכן את Grok. - רק התצורה שלך יכולה להגדיר זאת. שורת
commandמריצה תוכנית, ולכן היא נקראת מ-~/.grok/config.tomlשלך ומתצורה שמנהל המערכת שלך מנהל. מאגר אינו יכול להגדיר זאת: קובץ.grok/config.tomlמקומי של מאגר נקרא עבור שרתי MCP בלבד, ו-[ui.status_line]אינו בין המפתחות ששכבה ברמת פרויקט יכולה לספק, כך ששכפול מאגר אינו יכול לגרום ל-Grok להריץ את הסקריפט שלו. - תצורה שנדחפה לא השפיעה. הסעיף
[ui.status_line]מוסר מטלאים של קמפיינים ודריסת גרסאות (version-override), מכיוון ששורת מצב יכולה לציין פקודה שהמכונה שלך תריץ. הגדר אותו בקובץconfig.tomlשלך. - שגיאות. כל מה שהסקריפט שלך מדפיס מוצג, גם כאשר הוא יוצא עם קוד שאינו אפס, כך ש-
printf …; [[ -n $dirty ]]מתנהג כפי שאתה מצפה. סקריפט שאינו מדפיס דבר ונכשל מציג[status line: exit N], וזה נשאר עד שהריצה הבאה מצליחה, במקרה של ריצה שהופעלה על ידי מצב הפעלה, המדווחת על הכשל שלה מיד; כשל של ריצת טיימר שומר על הפלט האחרון במקום זאת (ראה הפעלות רענון). הפלט הסטנדרטי לשגיאות (stderr) של הסקריפט שלך לעולם אינו מוצג, כך שפקודתechoלצורכי ניפוי שגיאות לא תשבש את השורה; הרץ את Grok עם--debugכדי לקרוא אותו. סקריפט ש-Grok לא הצליח להפעיל כלל מציג[status line: could not start the script: …], שזה מה שמייצר קובץ ללא הרשאת ביצוע, וסקריפט שהמערכת מחסלת מציג[status line: killed by signal]. שורת#!המציינת מפרש חסר מנוסה מחדש תחתshבמקום זאת, ולכן היא מציגה קוד יציאה.