{ "name": "sidebar_survives_wide_writes", "cols": 120, "rows": 40, "scripts": [ { "name": "widewrite", "body": "#!/bin/sh\n# Reproduces a long-running TUI whose internal column state drifted\n# past the viewport width (the symptom seen in fucked-up-terminal.txt:\n# claude's input box drew a horizontal divider all the way to the host\n# edge, overwriting the sidebar). The widths here are: cols=120,\n# sidebarCols=28, so the viewport is 91 cols wide and the sidebar\n# border lives at col 92. Anything the child writes at col >= 92 lands\n# in the sidebar unless patterm defensively clamps it.\n#\n# After WIDE READY, emit 12 throw-away chunks to exhaust the focus\n# snapshot replay budget (8 chunks) so the wide-write clobber goes\n# through the *incremental* viewport renderer path. That's the path\n# that long-running sessions stay on — without clamping it can spray\n# bytes into the sidebar.\nprintf 'WIDE READY\\n'\ni=0\nwhile [ $i -lt 12 ]; do\n printf 'tick %d\\n' \"$i\"\n i=$((i + 1))\n sleep 0.05\ndone\nprintf 'PRE-CLOBBER\\n'\nsleep 0.2\nprintf '\\033[5;95HCLOBBER-CUP'\nsleep 0.1\nprintf '\\033[7;100HCLOBBER-CUP2'\nsleep 0.1\nprintf '\\033[9;1H'\nprintf '\\033[110GCLOBBER-CHA'\nprintf '\\nDONE\\n'\nsleep 5\n" } ], "steps": [ { "type": "mcp_call", "method": "spawn_process", "params": { "kind": "command", "argv": ["widewrite"], "name": "widewrite" } }, { "type": "wait_text", "contains": "WIDE READY", "timeout_ms": 5000 }, { "type": "wait_text", "contains": "DONE", "timeout_ms": 5000 }, { "type": "wait_stable", "timeout_ms": 2000 }, { "type": "assert_contains", "contains": "Agent Tree" }, { "type": "assert_contains", "contains": "Processes" }, { "type": "assert_contains", "contains": "Scratchpads" }, { "type": "assert_contains", "contains": "● widewrite" }, { "type": "assert_not_contains", "contains": "CLOBBER-CUP" }, { "type": "assert_not_contains", "contains": "CLOBBER-CHA" } ] }