diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/detect/manifest/tests.rs | 117 | ||||
| -rw-r--r-- | src/detect/manifests/grok.toml | 39 |
2 files changed, 144 insertions, 12 deletions
diff --git a/src/detect/manifest/tests.rs b/src/detect/manifest/tests.rs index bdb0789d..fc519c7f 100644 --- a/src/detect/manifest/tests.rs +++ b/src/detect/manifest/tests.rs @@ -725,6 +725,123 @@ fn osc_explain( ) } +#[test] +fn grok_osc_activity_does_not_depend_on_configurable_title_text() { + for (title, progress, expected_state, expected_rule) in [ + ( + "project · session · id", + "4;0;0", + AgentState::Idle, + "osc_progress_idle", + ), + ( + "project · session · id", + "", + AgentState::Idle, + "prompt_hints_idle", + ), + ("grok", "", AgentState::Idle, "osc_title_idle"), + ( + "⠋ - Waiting for response… - project", + "", + AgentState::Working, + "osc_title_working", + ), + ( + "project - ⠹ - session", + "4;0;0", + AgentState::Working, + "osc_title_working", + ), + ( + "project · session · id", + "4;1;-1", + AgentState::Working, + "osc_progress_working", + ), + ( + "grok", + "4;1;-1", + AgentState::Working, + "osc_progress_working", + ), + ( + "⚠ Action Required - project", + "4;1;-1", + AgentState::Blocked, + "osc_title_blocked", + ), + ] { + let result = osc_explain( + Agent::Grok, + "Shift+Tab:mode │ Ctrl+.:shortcuts\n", + title, + progress, + ); + assert_eq!( + result.state, expected_state, + "title={title}, progress={progress}" + ); + assert_eq!( + result.matched_rule.as_ref().map(|rule| rule.id.as_str()), + Some(expected_rule), + "title={title}, progress={progress}", + ); + } +} + +#[test] +fn grok_visible_activity_outranks_idle_osc_signals() { + for (screen, expected_rule) in [ + ( + "⠴ Sleep for 8 … 1.9s 5.0s ⇣19.5k [↓][stop]\n", + "spinner_status_working", + ), + ( + "Shift+Tab:mode │ Ctrl+c:cancel │ Ctrl+.:shortcuts\n", + "esc_cancel_hints_working", + ), + ( + "Shift+Tab:mode │ Esc:cancel │ Ctrl+.:shortcuts\n", + "esc_cancel_hints_working", + ), + ("◎ 1 command still running\n", "background_status_working"), + ("○ 1 command still running\n", "background_status_working"), + ("◉ 1 command still running\n", "background_status_working"), + ( + "◎ 2 commands · 1 subagent still running · send a message to interrupt\n", + "background_status_working", + ), + ] { + for progress in ["", "4;0;0"] { + let result = osc_explain(Agent::Grok, screen, "grok", progress); + assert_eq!(result.state, AgentState::Working, "screen={screen}"); + assert_eq!( + result.matched_rule.as_ref().map(|rule| rule.id.as_str()), + Some(expected_rule) + ); + } + let blocked = osc_explain(Agent::Grok, screen, "⚠ Action Required - grok", "4;1;-1"); + assert_eq!(blocked.state, AgentState::Blocked); + } +} + +#[test] +fn grok_background_activity_requires_a_live_nonzero_status_row() { + for screen in [ + "1 command still running\n", + "◎ 0 commands still running\n", + "Discussed: ◎ 1 command still running\n", + "◎ 1 command still running\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n", + "Worked for 3.9s\nShift+Tab:mode │ Ctrl+.:shortcuts\n", + ] { + assert_eq!( + osc_explain(Agent::Grok, screen, "project · session", "4;0;0").state, + AgentState::Idle + ); + } +} + // --- Claude OSC rules --- #[test] diff --git a/src/detect/manifests/grok.toml b/src/detect/manifests/grok.toml index 30b6e9c7..67ba4ebc 100644 --- a/src/detect/manifests/grok.toml +++ b/src/detect/manifests/grok.toml @@ -1,16 +1,16 @@ id = "grok" -version = "2026.07.16.2" +version = "2026.09.18.2" min_engine_version = 3 -updated_at = "2026-07-16T00:00:00Z" +updated_at = "2026-09-18T00:00:00Z" aliases = ["grok-build"] -# Evidence: Grok Build 0.2.101 source and live pane reads. +# Evidence: Grok Build 0.2.101 source and 1.0.34 live pane reads. # # Grok emits OSC 0 titles by default. Idle is "grok" or # "<session> - grok". During a turn, the configured title gains a braille # spinner and activity text. Permission prompts add "⚠ Action Required"; # that prefix blinks while the terminal is unfocused, so visible blocker -# rules outrank the generic non-idle title rule. +# rules outrank the title spinner rule. # # Grok also emits OSC 9;4 progress on supported terminals. Herdr retains the # payload after "9;": "4;1;-1" while busy and "4;0;0" when idle. @@ -85,6 +85,16 @@ region = "top_non_empty_lines(1)" visible_working = true line_regex = ['[⋅:⸬⁙.·]\s+[1-9][0-9]*\s+│'] +# Grok 1.0.34 moves background counts above the composer and clears OSC +# progress between turns even while these commands are still running. +[[rules]] +id = "background_status_working" +state = "working" +priority = 1165 +region = "bottom_non_empty_lines(12)" +visible_working = true +line_regex = ['^\s*[○◎◉]\s+[1-9][0-9]*\s+(?:commands?|monitors?|loops?|subagents?)(?:\s+·\s+[1-9][0-9]*\s+(?:commands?|monitors?|loops?|subagents?))*\s+still running(?:\s+·\s+send a message to interrupt)?\s*$'] + [[rules]] id = "osc_progress_working" state = "working" @@ -104,16 +114,15 @@ not = [ { regex = ['[\x{2800}-\x{28FF}]'] }, ] -# After known idle titles are excluded, any other non-empty Grok title is -# active. OSC progress remains authoritative when a custom title omits the -# spinner but the terminal supports progress reporting. +# Title items are configurable; omitting "grok" does not imply activity. +# Require a spinner, with OSC progress covering titles that omit it. [[rules]] id = "osc_title_working" state = "working" priority = 1000 region = "osc_title" visible_working = true -regex = ['\S'] +regex = ['(?:^|\s)[\x{2801}-\x{28FF}](?:\s|$)'] [[rules]] id = "osc_progress_idle" @@ -123,10 +132,12 @@ region = "osc_progress" visible_idle = true regex = ['^4;0;0$'] +# Visible activity outranks idle OSC signals: disabling title updates can +# leave the startup "grok" title unchanged throughout a turn. [[rules]] id = "spinner_status_working" state = "working" -priority = 200 +priority = 1160 region = "whole_recent" visible_working = true line_regex = ['^\s*[\x{2801}-\x{28FF}]\s.*\[stop\]\s*$'] @@ -134,16 +145,20 @@ line_regex = ['^\s*[\x{2801}-\x{28FF}]\s.*\[stop\]\s*$'] [[rules]] id = "esc_cancel_hints_working" state = "working" -priority = 190 +priority = 1155 region = "bottom_non_empty_lines(2)" visible_working = true -contains = ["esc:cancel", "ctrl+.:shortcuts"] +contains = ["ctrl+.:shortcuts"] +any = [ + { contains = ["esc:cancel"] }, + { contains = ["ctrl+c:cancel"] }, +] # Pre-0.2.x working chrome kept for older Grok Build releases. [[rules]] id = "waiting_tool_working" state = "working" -priority = 120 +priority = 1140 region = "whole_recent" visible_working = true any = [ |
