fix(tui): kept ssh partial result commit-unstable

Reviewer flagged that ToolExecutionComponent.isTranscriptBlockCommitStable\ntreated any block with a defined #result as commit-stable, so a long\nstreaming SSH partial render could sit on its stable pending header until\nderiveLiveCommitState's stable-prefix ratchet promoted it to native\nscrollback, then the final SSH glyph render would land below and strand a\nduplicate pending header above the settled frame.\n\n- Added ToolRenderer.provisionalPartialResult opt-in for renderers whose\n  partial-result chrome differs from the final render.\n- Honored it in ToolExecutionComponent.isTranscriptBlockCommitStable so the\n  block stays commit-unstable while isPartial holds and flips stable as soon\n  as the result settles.\n- Set provisionalPartialResult: true on the SSH renderer.\n- Added test/tools/ssh-commit-stability.test.ts covering the partial/final\n  transition and the non-regression for bash.\n\nFixes #3177
This commit is contained in:
roboomp
2026-06-21 08:13:56 +00:00
parent 5910ae32b4
commit 3faeddd3a6
5 changed files with 113 additions and 10 deletions
@@ -52,6 +52,17 @@ export type ToolRenderer = {
* streams rows the result render preserves.
*/
provisionalPendingPreview?: boolean | "collapsed";
/**
* Whether the partial-result render is provisional: chrome rows (header
* glyph, frame state) that change between `options.isPartial === true` and
* the final result render. When `true`, the block is treated as
* commit-unstable while a partial result is in flight, so the
* stable-prefix ratchet in `deriveLiveCommitState` cannot promote the
* partial chrome to native scrollback only to have the final render strand
* it above the settled frame. Absent = the partial render is byte-stable
* with the final render and may commit like any settled stream.
*/
provisionalPartialResult?: boolean;
};
export const toolRenderers: Record<string, ToolRenderer> = {
+8
View File
@@ -373,4 +373,12 @@ export const sshToolRenderer = {
// that shifts while args stream. Expanded output is top-anchored enough for
// the transcript to commit its settled prefix.
provisionalPendingPreview: "collapsed",
// Partial-result chrome (pending icon and frame state) differs from the
// final SSH glyph/state, so the block stays commit-unstable while
// `options.isPartial` holds. Without this, a long-running SSH command's
// stable pending header would be promoted by the stable-prefix ratchet and
// committed to native scrollback, then the final render's SSH glyph would
// land below and strand a duplicate pending header above the final frame
// ([#3177](https://github.com/can1357/oh-my-pi/issues/3177)).
provisionalPartialResult: true,
};