fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view - #1140

Merged
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback
Jul 16, 2026
Merged

fix(cli): flip the expansion default and explain when Ctrl+O/Ctrl+T finds no block in view#1140
Astro-Han merged 2 commits into
mainfrom
fix/cli-headscrolled-toggle-feedback

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Closes#1134. Follow-up to #1097 / #1130.

Expanding a block taller than the terminal pushes the block's own head above the live viewport into terminal scrollback. Scrollback is append-only, so collapsing that block in place is physically impossible without the scrollback-clearing full redraw the #1097 contract forbids — the second Ctrl+O/Ctrl+T found no in-viewport target, returned false, and silently left both the block and the expansion default stuck.

Per the decision on #1134, this accepts the physical limitation instead of "fixing" it (option 3), and removes the two real defects around it:

Not done, deliberately: clamping expanded rendering (regresses full-content-into-scrollback), letting toggles touch head-scrolled blocks (reintroduces the #1097 wipe), or an explicit scrollback-clearing redraw command (possible orthogonal follow-up).

Verification

  • packages/cli: npm test 465/465 (3 new/updated unit tests, 1 new integration test), root npm run lint clean.
  • New unit tests lock: head-scrolled second toggle flips the default back, freezes the entry, keeps scrollback lines byte-identical, and appends the notice; a session with no candidate still reports nothing to toggle; the post-replacement inert window is preserved.
  • New integration test drives the real pi-tui renderer through runMakaPiTui with a 24-row terminal: an 80-line thinking block is expanded past the viewport, the second Ctrl+T renders the notice, and the whole output stream contains no ESC[3J.
  • Manually drove the built TUI in a real tmux TTY (100×24): expanded an 80-line thinking block (head scrolled into tmux scrollback), pressed Ctrl+T again → notice rendered, expansion frozen, all 80 rows still present in tmux scrollback with no screen clear; Ctrl+O on the in-viewport tool card still round-trips expand/collapse.
 reason-row-78
reason-row-79
● Bash $ npm test (41 lines)
done answering
Note: No thinking in view to toggle — thinking above stays as rendered in scrollback. New thinking
starts collapsed.

…inds no block in view
A block expanded past the terminal pushes its own head into scrollback,
which the #1097 contract forbids rewriting, so the second Ctrl+O/Ctrl+T
found no target, returned false, and silently left both the block and
the expansion default stuck.
The toggles now always flip the default when any candidate entry exists
and positions are known; when every candidate sits above the viewport
they append an info notice saying the content stays readable in
scrollback and which state new output starts in. Toggles stay fully
inert while entry positions are unknown after a wholesale replacement,
and entries above the viewport stay byte-identical as before.
Closes#1134
@Astro-Han
Astro-Han merged commit e96f8b7 into mainJul 16, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/cli-headscrolled-toggle-feedback branch July 24, 2026 09:05
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 28, 2026
…primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
likun666661 pushed a commit that referenced this pull request Aug 28, 2026
…bove the viewport (#4011) (#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the #1097
contract forbids rewriting, so they stay expanded with no way back
(#1134). #1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (#1134 option 2,
deferred by #1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
saltand pushed a commit to saltand/maka-agent that referenced this pull request Aug 31, 2026
…bove the viewport (apache#4011) (apache#4025)
* feat(cli): name stranded expansion blocks and add confirmed-collapse primitives (apache#4011)
A Ctrl+O/Ctrl+T collapse can strand expanded blocks above the live
viewport: their heads sit in terminal scrollback, which the apache#1097
contract forbids rewriting, so they stay expanded with no way back
(apache#1134). apache#1140 made the all-stranded case explained but left the far
more common partial case silent — some cards collapse, some stay stuck,
and the keypress reads as broken.
The toggle now appends a notice whenever a collapse strands blocks,
naming the count and offering the escape hatch: a second press within
EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS collapses them too via one
knowingly-accepted, scrollback-clearing full redraw (apache#1134 option 2,
deferred by apache#1140 as an orthogonal follow-up). The confirm offer exists
for collapses only — collapsed blocks above the viewport are compact
and harmless, and arming on expand would make a quick expand-then-
collapse pair read the second press as "expand everything".
New exports for the runner wiring: hasExpandedEntriesAboveViewport
(arming predicate) and applyExpansionDefaultToAll (applies the current
default to every entry including above-viewport ones, without flipping
the default the way a plain toggle would). The window constant lives
beside the notice copy so the offer text and the runner's confirm
window share one authority.
Generated-by: OpenCode
* feat(cli): second Ctrl+O/Ctrl+T press pays one full redraw to collapse stranded blocks (apache#4011)
Wire the confirm gesture into the key handler: a collapse toggle that
leaves expanded blocks above the viewport arms a 2s window; pressing
the same key again inside it applies the collapsed default to every
entry and forces one scrollback-clearing full redraw through pi-tui's
existing public requestRender(true), which re-anchors the viewport at
the tail. Transcript content is fully re-rendered into fresh scrollback,
so nothing from the session is lost; only pre-session shell scrollback
is cleared, and only after the explicit second press the notice
announced.
The integration test drives the real renderer on a 24-row terminal: an
80-line thinking block is expanded past the viewport, the first collapse
press renders the offer with no ESC[3J in the stream, and the confirmed
second press emits exactly the deliberate clear while collapsing the
block back to its compact row.
Generated-by: OpenCode
* fix(cli): re-offer expired expansion confirmation
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): a block expanded past the viewport cannot be collapsed again

1 participant

@Astro-Han