From 887d7bc186db90c3903851b0f1db2d24df5d7a7b Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 8 Feb 2026 15:19:36 +0200 Subject: fix hexai-tmux-edit agent detection, multi-line extraction, and clearing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reorder agents: cursor first to avoid false positive from "Claude 4.5 Sonnet" model name appearing in cursor panes - Change cursor detect pattern to box-drawing UI elements instead of name-based matching - Change claude detect pattern to ❯ prompt instead of generic "claude" - Support multi-line prompt extraction using last-contiguous-block algorithm to ignore command-review and dialog boxes - Fix deduplicateText to always return full edited text (clear + resend) instead of stripping original prefix which caused double-removal - Replace vim-style clear (Escape gg dG i) with universal End+BSpace*200 since cursor's prompt is not actually vim - Add Key*N repeat syntax in ClearKeys (parsed by parseKeyRepeat, sent via tmux send-keys -N) - Add 300ms sleep after clear to let TUI drain queued backspaces before new text arrives - Add debug logging to /tmp/hexai-tmux-edit.log - Add strip pattern for "ctrl+c to stop" noise in cursor prompt Co-Authored-By: Claude Opus 4.6 --- internal/tmuxedit/agent_test.go | 71 ++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 11 deletions(-) (limited to 'internal/tmuxedit/agent_test.go') diff --git a/internal/tmuxedit/agent_test.go b/internal/tmuxedit/agent_test.go index a6bc20d..7ad1274 100644 --- a/internal/tmuxedit/agent_test.go +++ b/internal/tmuxedit/agent_test.go @@ -15,9 +15,11 @@ func TestDetectAgent(t *testing.T) { content string want string }{ - {"claude from banner", "Welcome to Claude Code v1.2\n> ", "claude"}, - {"claude from anthropic", "Powered by Anthropic\n> ", "claude"}, - {"cursor from prompt", "cursor agent ready\n│ type here", "cursor"}, + {"claude code prompt", "────\n❯ hello world\n────", "claude"}, + {"claude code banner", "claude code v1.2\n❯ ", "claude"}, + {"claude from anthropic", "Powered by Anthropic\n❯ ", "claude"}, + {"cursor box ui", "│ → type here │\n/ commands · @ files", "cursor"}, + {"cursor not false claude", "Claude 4.5 Sonnet\n│ → test │\n/ commands · @ files", "cursor"}, {"amp from banner", "Amp by Sourcegraph\n> ", "amp"}, {"aider from banner", "aider v0.50\n> /help", "aider"}, {"no match", "some random terminal output\n$ ", "generic"}, @@ -64,22 +66,69 @@ func TestExtractPrompt(t *testing.T) { }{ { name: "claude prompt", - content: "Claude Code v1\n> hello world", - agent: builtinAgents()[0], // claude + content: "────\n❯ hello world\n────", + agent: builtinAgents()[1], // claude want: "hello world", }, { - name: "cursor prompt with strip", - content: "Cursor Agent\n│ fix the bug INSERT", - agent: builtinAgents()[1], // cursor + name: "cursor prompt with box and arrow", + content: "Cursor Agent\n │ → fix the bug INSERT │", + agent: builtinAgents()[0], // cursor + want: "fix the bug", + }, + { + name: "cursor prompt without arrow", + content: "Cursor Agent\n │ fix the bug │", + agent: builtinAgents()[0], // cursor want: "fix the bug", }, { name: "cursor prompt strips follow-up", - content: "Cursor\n│ Add a follow-up", - agent: builtinAgents()[1], // cursor + content: "Cursor\n │ → Add a follow-up │", + agent: builtinAgents()[0], // cursor want: "", }, + { + name: "cursor multi-line prompt", + content: " │ → first line of prompt │\n │ second line here │\n │ third line end │", + agent: builtinAgents()[0], // cursor + want: "first line of prompt\nsecond line here\nthird line end", + }, + { + name: "cursor multi-line with noise", + content: " │ → fix the bug INSERT │\n │ also refactor tests │", + agent: builtinAgents()[0], // cursor + want: "fix the bug\nalso refactor tests", + }, + { + name: "cursor multi-box takes last box only", + content: " ┌──────────────┐\n" + + " │ $ git push │\n" + + " └──────────────┘\n" + + " ┌──────────────┐\n" + + " │ Run command? │\n" + + " │ → Yes (enter) │\n" + + " │ No (esc) │\n" + + " └──────────────┘\n" + + " ┌──────────────┐\n" + + " │ → hello world │\n" + + " └──────────────┘\n", + agent: builtinAgents()[0], // cursor + want: "hello world", + }, + { + name: "cursor multi-box multi-line prompt", + content: " ┌──────────────┐\n" + + " │ $ git push │\n" + + " └──────────────┘\n" + + " ┌──────────────┐\n" + + " │ → first line │\n" + + " │ second line │\n" + + " │ third line │\n" + + " └──────────────┘\n", + agent: builtinAgents()[0], // cursor + want: "first line\nsecond line\nthird line", + }, { name: "no pattern", content: "some text", @@ -89,7 +138,7 @@ func TestExtractPrompt(t *testing.T) { { name: "no match", content: "no prompt here", - agent: builtinAgents()[0], // claude + agent: builtinAgents()[1], // claude want: "", }, { -- cgit v1.2.3