diff options
Diffstat (limited to 'crates/detect-core/src/manifests/claude.toml')
| -rw-r--r-- | crates/detect-core/src/manifests/claude.toml | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/crates/detect-core/src/manifests/claude.toml b/crates/detect-core/src/manifests/claude.toml new file mode 100644 index 0000000..0c7bdcf --- /dev/null +++ b/crates/detect-core/src/manifests/claude.toml @@ -0,0 +1,230 @@ +id = "claude" +version = "2026.09.11.1" +min_engine_version = 2 +updated_at = "2026-09-11T00:00:00Z" +aliases = ["claude-code"] + +[[rules]] +id = "osc_title_working" +state = "working" +priority = 1100 +region = "osc_title" +visible_working = true +# Braille covers <= 2.1.227; half-circles are the 2.1.228 busy spinner. +regex = ['^[\x{2800}-\x{28FF}\x{25D0}-\x{25D3}] '] + +[[rules]] +id = "live_turn_working" +state = "working" +priority = 970 +region = "bottom_non_empty_lines(12)" +visible_working = true +any = [ + { line_regex = ['^\s*[⏸⏵].*esc to interrupt(?:\s|·|$)'] }, + { line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2733}\x{2736}\x{273B}\x{273D}]\s+\S.*…(?:\s+\(\d+[smh](?:\s|·)|\s*$)'] }, +] + +[[rules]] +id = "background_agents_working" +state = "working" +priority = 965 +region = "last_non_empty_above_prompt_box" +visible_working = true +line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}]\s+Waiting for [1-9]\d* background agents? to finish\s*$'] + +[[rules]] +id = "background_mcp_task_working" +state = "working" +priority = 965 +region = "bottom_non_empty_lines(12)" +visible_working = true +# Claude renders activity summaries at column zero; wrapped continuations are indented. +# Keeping that shape prevents user prompt text from impersonating this signal. +regex = ['(?m)^[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}][ \t]+\S[^\n]*?(?:\n[ \t]+[^\n]*?){0,3}·(?:[ \t]+|\n[ \t]*)[1-9]\d*(?:[ \t]+|\n[ \t]*)MCP(?:[ \t]+|\n[ \t]*)tasks?(?:[ \t]+|\n[ \t]*)still(?:[ \t]+|\n[ \t]*)running[ \t]*$'] +not = [ + { contains = ["do you want to proceed?"] }, + { contains = ["esc to cancel"] }, + { contains = ["waiting for permission"] }, + { contains = ["do you want to allow this connection?"] }, + { contains = ["tab to amend"] }, + { contains = ["ctrl+e to explain"] }, +] + +[[rules]] +id = "btw_overlay_working" +state = "working" +priority = 975 +region = "bottom_non_empty_lines(5)" +visible_working = true +line_regex = [ + '^\s*/btw(?:\s|$)', + '(?i)esc to close\s*$', +] + +[[rules]] +id = "transcript_viewer" +state = "unknown" +priority = 1000 +region = "bottom_non_empty_lines(3)" +skip_state_update = true +contains = ["showing detailed transcript"] +any = [ + { contains = ["ctrl+o", "to toggle"] }, + { contains = ["ctrl+e", "show all"] }, + { contains = ["ctrl+e", "collapse"] }, + { contains = ["↑↓ scroll"] }, + { contains = ["? for shortcuts"] }, +] + +[[rules]] +id = "live_blocked_form" +state = "blocked" +priority = 980 +region = "after_last_horizontal_rule" +visible_blocker = true +contains = ["esc to cancel"] +any = [ + { contains = ["enter to confirm"] }, + { contains = ["enter to select"], any = [ + { contains = ["tab/arrow keys to navigate"] }, + { contains = ["arrow keys to navigate"] }, + { contains = ["arrows to navigate"] }, + { contains = ["↑/↓ to navigate"] }, + { contains = ["↑↓ to navigate"] }, + ] }, +] + +[[rules]] +id = "dynamic_workflow_prompt" +state = "blocked" +priority = 980 +region = "whole_recent" +visible_blocker = true +contains = ["run a dynamic workflow?", "esc to cancel"] + +[[rules]] +id = "mcp_elicitation_prompt" +state = "blocked" +priority = 980 +region = "whole_recent" +visible_blocker = true +# MCP elicitation dialogs (elicitation/create) show Accept/Decline controls +# with an "Esc to cancel" footer but no Enter hint, so live_blocked_form +# cannot see them (issue #3283). Gate on the invariant header line, the +# Accept/Decline control line, and the cancel footer. +contains = ["esc to cancel"] +line_regex = ['(?i)^\s*MCP server ["\x{201C}].+["\x{201D}] requests your input\s*$'] +all = [ + { any = [ + { line_regex = ['^\s*\x{276F}?\s*Accept\b'] }, + { line_regex = ['^\s*\x{276F}?\s*Decline\b'] }, + ] }, +] + +[[rules]] +id = "live_prompt_box" +state = "idle" +priority = 950 +region = "prompt_box_body" +visible_idle = true +line_regex = ['^\s*❯'] +not = [ + { contains = ["enter to select"] }, + { contains = ["esc to cancel"] }, + { contains = ["tab/arrow keys"] }, + { contains = ["arrow keys to navigate"] }, + { contains = ["↑/↓ to navigate"] }, +] + +[[rules]] +id = "model_picker_menu" +state = "unknown" +priority = 900 +region = "whole_recent" +skip_state_update = true +contains = ["select model", "enter to set as default", "esc to cancel"] +not = [ + { contains = ["do you want to proceed?"] }, + { contains = ["enter to select"] }, +] + +[[rules]] +id = "bash_permission_prompt" +state = "blocked" +priority = 850 +region = "whole_recent" +visible_blocker = true +contains = ["do you want to proceed?"] +any = [ + { contains = ["bash command"] }, + { contains = ["bash("] }, + { contains = ["contains expansion"] }, + { contains = ["tab to amend"] }, + { contains = ["ctrl+e to explain"] }, +] +# Claude marks the selected option with "❯", so every option branch has to allow +# that prefix. Numbered branches that omit it only match options the cursor has +# moved away from, which left the resting layout below unmatched here (#2650): +# ❯ 1. Yes / 2. Yes, and don't ask again for: <cmd> / 3. No +# Cover both the two-option and "don't ask again" three-option shapes so this +# rule, not the narrower generic_permission_prompt, claims Bash approvals. +all = [ + { any = [ + { line_regex = ['(?i)^\s*❯?\s*yes\b'] }, + { line_regex = ['(?i)^\s*❯?\s*1\.\s*yes\b'] }, + { line_regex = ['(?i)^\s*❯?\s*2\.\s*yes\b'] }, + { line_regex = ['(?i)^\s*❯?\s*2\.\s*no\b'] }, + { line_regex = ['(?i)^\s*❯?\s*3\.\s*no\b'] }, + ] }, +] + +[[rules]] +id = "generic_permission_prompt" +state = "blocked" +priority = 840 +region = "after_last_horizontal_rule" +visible_blocker = true +contains = ["do you want to proceed?", "esc to cancel"] +all = [ + { any = [ + { line_regex = ['(?i)^\s*❯?\s*1\.\s*yes\b'] }, + { line_regex = ['(?i)^\s*2\.\s*yes\b'] }, + { line_regex = ['(?i)^\s*2\.\s*no\b'] }, + { line_regex = ['(?i)^\s*3\.\s*no\b'] }, + ] }, +] + +[[rules]] +id = "legacy_no_prompt_blocker" +state = "blocked" +priority = 300 +region = "whole_recent" +any = [ + { contains = ["do you want to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, + { contains = ["would you like to"], any = [{ contains = ["yes"] }, { contains = ["❯"] }] }, + { contains = ["waiting for permission"] }, + { contains = ["do you want to allow this connection?"] }, + { contains = ["tab to amend"] }, + { contains = ["ctrl+e to explain"] }, + { contains = ["do you want to proceed?", "esc to cancel"] }, + { contains = ["review your answers"] }, + { contains = ["skip interview and plan immediately"] }, +] +not = [ + { regex = ['(?m)^\s*❯\s*$'] }, +] + +[[rules]] +id = "osc_title_idle" +state = "idle" +priority = 250 +region = "osc_title" +visible_idle = true +regex = ['^\x{2733} '] + +[[rules]] +id = "osc_progress_idle" +state = "idle" +priority = 250 +region = "osc_progress" +regex = ['^4;0'] |
