summaryrefslogtreecommitdiff
path: root/internal/tmuxedit/cursor_agent.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-08 16:31:40 +0200
committerPaul Buetow <paul@buetow.org>2026-02-08 16:31:40 +0200
commitc802ba5803de1a53749bb5c4ecbc0159fceb385f (patch)
tree02e612286f36bc6c65563bc33cf53639817d2db1 /internal/tmuxedit/cursor_agent.go
parent887d7bc186db90c3903851b0f1db2d24df5d7a7b (diff)
refactor tmuxedit to Agent interface with cursor/claude/config implementations
Replace monolithic AgentConfig struct with an Agent interface backed by baseAgent defaults and separate implementations for cursor (box-drawing extraction, bulk backspace clearing) and claude (section-scoped extraction with continuation lines, vim clearing). Simple agents (amp, aider) and user-defined agents use configAgent with baseAgent defaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/tmuxedit/cursor_agent.go')
-rw-r--r--internal/tmuxedit/cursor_agent.go58
1 files changed, 58 insertions, 0 deletions
diff --git a/internal/tmuxedit/cursor_agent.go b/internal/tmuxedit/cursor_agent.go
new file mode 100644
index 0000000..1346d05
--- /dev/null
+++ b/internal/tmuxedit/cursor_agent.go
@@ -0,0 +1,58 @@
+package tmuxedit
+
+import (
+ "regexp"
+)
+
+// cursorAgent handles Cursor's distinctive box-drawing │ → prompt │ UI.
+// Cursor uses a text field (not vim), so clearing is done with End + bulk
+// backspace. Multi-line prompts are entered with Shift-Enter within the box.
+type cursorAgent struct{ baseAgent }
+
+// newCursorAgent returns a cursorAgent with the default configuration.
+// Detect by the box structure or "/ commands" footer. Checked first because
+// cursor panes often show model names like "Claude 4.5 Sonnet".
+func newCursorAgent() *cursorAgent {
+ return &cursorAgent{baseAgent{
+ name: "cursor",
+ displayName: "Cursor",
+ detectPattern: `(│\s*→|/ commands · @ files)`,
+ promptPat: `(?m)│\s*→?\s*(.+?)\s*│\s*$`,
+ stripPatterns: []string{"INSERT", "Add a follow-up", "ctrl+c to stop"},
+ clearFirst: true,
+ clearKeys: "End BSpace*200",
+ newlineKeys: "S-Enter",
+ submitKeys: "Enter",
+ }}
+}
+
+// ExtractPrompt extracts the prompt text from the last contiguous │...│ block
+// in the pane. This avoids picking up earlier command-review or dialog boxes
+// that also use box-drawing characters.
+func (c *cursorAgent) ExtractPrompt(paneContent string) string {
+ if c.promptPat == "" {
+ return ""
+ }
+ re, err := regexp.Compile(c.promptPat)
+ if err != nil {
+ return ""
+ }
+ allMatches := matchPromptLines(re, paneContent)
+ if len(allMatches) == 0 {
+ return ""
+ }
+ return joinLastContiguousBlock(allMatches, c.stripPatterns)
+}
+
+// ClearInput sends End + 200 backspaces to clear Cursor's text field.
+// Cursor's input is a standard text field, not vim.
+func (c *cursorAgent) ClearInput(paneID string) error {
+ if !c.clearFirst || c.clearKeys == "" {
+ return nil
+ }
+ if err := sendClearSequence(paneID, c.clearKeys); err != nil {
+ return err
+ }
+ sleepAfterClear()
+ return nil
+}