Land staged session/MCP/chrome work + sidebar clear-J fix
This batches the in-flight [Unreleased] block from CHANGELOG.md into a single commit. Highlights: - Real MCP protocol layer (initialize / tools/list / tools/call) so vendor MCP clients can complete the handshake against the per-PID socket. Legacy direct-dispatch preserved for the harness. - New mcp_injection kinds — cli_override for codex, config_env for opencode — joining the existing env-var and config_file paths so patterm can slot into more agents without touching their real config or auth. - Ctrl+A/D and Ctrl+W/S focus navigation across tabs and intra-tab process lists, recognised in legacy / kitty CSI u / xterm modifyOtherKeys encodings. - Palette macros (sw / k / sp ) and reordering so open sessions surface above spawn-new entries. - Two-row tab bar, sidebar/tabbar/status chrome cache, viewport-wipe on agent spawn, CR-terminated orchestrator injections, and split- Enter PTY writes so paste-detecting TUIs see Enter as a key event. Also fixes the bug logged in TODO: claude's Ctrl+O tool-call expansion emits CSI 0 J, which the viewport renderer was forwarding verbatim — wiping the sidebar to the right of the cursor and leaving the chrome cache convinced nothing had changed. CSI 0 J and CSI 1 J are now translated into per-row ECH sequences clamped to the viewport, same as CSI 2 J and CSI K already were. Agent guides (CLAUDE.md / AGENTS.md) now spell out the TODO->CHANGELOG workflow so completed items land in the changelog rather than as ticked entries left behind in TODO.
This commit is contained in:
@@ -161,6 +161,10 @@ func (vr *viewportRenderer) emitCSI() {
|
||||
return
|
||||
}
|
||||
switch n {
|
||||
case 0:
|
||||
vr.pending.WriteString(vr.clearViewportFromCursor())
|
||||
case 1:
|
||||
vr.pending.WriteString(vr.clearViewportToCursor())
|
||||
case 2, 3:
|
||||
vr.pending.WriteString(vr.clearViewport())
|
||||
default:
|
||||
@@ -203,6 +207,54 @@ func (vr *viewportRenderer) clearViewport() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// clearViewportFromCursor implements `CSI 0 J` clamped to the viewport.
|
||||
// Without clamping, the child's "clear to end of screen" would reach the
|
||||
// rightmost columns and erase the sidebar.
|
||||
func (vr *viewportRenderer) clearViewportFromCursor() string {
|
||||
row, col := vr.row, vr.col
|
||||
cols := int(vr.layout.childCols())
|
||||
rows := int(vr.layout.childRows())
|
||||
if row < 1 {
|
||||
row = 1
|
||||
}
|
||||
if col < 1 {
|
||||
col = 1
|
||||
}
|
||||
var b strings.Builder
|
||||
b.WriteString("\x1b7")
|
||||
if remaining := cols - col + 1; remaining > 0 {
|
||||
fmt.Fprintf(&b, "\x1b[%dX", remaining)
|
||||
}
|
||||
for r := row + 1; r <= rows; r++ {
|
||||
fmt.Fprintf(&b, "\x1b[%d;%dH\x1b[%dX",
|
||||
int(vr.layout.mainTop)+r-1, int(vr.layout.mainLeft), cols)
|
||||
}
|
||||
b.WriteString("\x1b8")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// clearViewportToCursor implements `CSI 1 J` clamped to the viewport.
|
||||
func (vr *viewportRenderer) clearViewportToCursor() string {
|
||||
row, col := vr.row, vr.col
|
||||
cols := int(vr.layout.childCols())
|
||||
if row < 1 {
|
||||
row = 1
|
||||
}
|
||||
if col < 1 {
|
||||
col = 1
|
||||
}
|
||||
var b strings.Builder
|
||||
b.WriteString("\x1b7")
|
||||
for r := 1; r < row; r++ {
|
||||
fmt.Fprintf(&b, "\x1b[%d;%dH\x1b[%dX",
|
||||
int(vr.layout.mainTop)+r-1, int(vr.layout.mainLeft), cols)
|
||||
}
|
||||
fmt.Fprintf(&b, "\x1b[%d;%dH\x1b[%dX",
|
||||
int(vr.layout.mainTop)+row-1, int(vr.layout.mainLeft), col)
|
||||
b.WriteString("\x1b8")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (vr *viewportRenderer) clearLine(n int) string {
|
||||
right := int(vr.layout.childCols())
|
||||
if vr.col < 1 {
|
||||
|
||||
Reference in New Issue
Block a user