Skip to content

feat(rpc): render extension components in the shared host - #1219

Merged
code-yeongyu merged 27 commits into
mainfrom
fix/shared-host-extension-ui
Aug 30, 2026
Merged

feat(rpc): render extension components in the shared host#1219
code-yeongyu merged 27 commits into
mainfrom
fix/shared-host-extension-ui

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Problem

Extension UI degrades in the shared host (RPC mode): component-factory widgets (btw panel, todo-sidebar, prompt-url) trigger the "requires the classic TUI" custom_unsupported warning instead of rendering, and setHeader/setFooter factories are silently dropped (connection-handler.ts).

Ideal state (this PR)

Every extension widget/component renders correctly in the shared host, so the classic-TUI-only warning path is never triggered for built-in components.

  • New src/modes/rpc/widget-line-renderer.ts: createLiveComponentRenderer() renders component factories server-side into text lines — synchronous first render, coalesced requestRender, unchanged-output suppression, immediate rerender(), disposal, factory/render fault isolation, global theme pass-through.
  • setWidget factory branch now emits the EXISTING additive setWidget lines message (rendered output); the custom_unsupported degradation for widget components is deleted. ctx.ui.custom() keeps its opt-in notice.
  • setHeader/setFooter forwarded as new additive extension_ui_request methods carrying rendered lines.
  • New additive client->server command set_client_info { width }; per-connection width (default 80) with live rerender on change. Attached interactive clients send width on attach and on SIGWINCH.
  • Docs: docs/rpc.md + src/modes/rpc/changes.md updated in the same increment.

Additive-only: a default client that ignores unknown methods and never sends set_client_info sees byte-identical behavior for everything it already used.

TDD / evidence (run on a clean remote box)

  • Renderer contract: RED (module missing) -> GREEN 8/8 (test/suite/rpc-widget-line-renderer.test.ts).
  • Wiring: RED 10-fail -> GREEN 14/14 (test/rpc-socket-host.test.ts): factory widget renders w:80, header/footer additive methods, ZERO custom_unsupported asserted.
  • Width: mutation proof — removing the set_client_info rerender loop fails the pin; restored = 14/14.
  • Real-surface QA (scripted, committed driver test/manual-qa/shared-host-widget-qa.mts): real socket host + real todotools builtin over the wire -> rendered todo-sidebar lines, zero custom_unsupported, width-60 rerender. QA-PASS transcript captured.
  • Full packages/coding-agent suite + root npm run check on the branch; the only full-suite failures (app-server daemon/stdio) reproduce as box-contention flakes: they pass 68/68 focused on this branch AND on origin/main.

Summary by cubic

Renders extension component widgets, headers, and footers in the shared RPC host instead of dropping them or showing the custom_unsupported warning. Clients that advertise rendered_components via the new set_client_info command receive factory-rendered text lines; clients that ignore unknown methods see byte-identical behavior.

  • setWidget factories render server-side into text lines; the widget custom_unsupported degradation is gone, while ctx.ui.custom() keeps its opt-in notice.
  • setHeader and setFooter are new additive extension_ui_request methods; footer factories receive a session-backed footer data provider.
  • Width defaults to 80, rerenders live on change, and is forgotten when a connection closes.
  • Capability registration is connection-wide, survives additional session opens, and is scoped to socket sessions; closing a session removes only its width, while socket release clears the registration.
  • Bindings retain factories when no capable connection remains and recreate renderers and footer providers for later capable joiners.
  • Snapshot replay applies the same per-connection capability filter, so late joiners only receive rendered records they opted into.
  • Interactive hosts advertise rendered_components, report terminal width with live resize updates, re-register after reconnect, and buffer startup UI events so session-start widgets reach the runtime API before the normal listener is installed.
  • Renderer faults are isolated without dropping the connection; recovered renders re-emit even when they match the last successful frame.

Written for commit e425816. Summary will update on new commits.

Review in cubic

@code-yeongyu
code-yeongyu force-pushed the fix/shared-host-extension-ui branch 5 times, most recently from cd4e7cb to 8491434 Compare August 30, 2026 16:18
@code-yeongyu
code-yeongyu force-pushed the fix/shared-host-extension-ui branch from d5d6a9f to e842d33 Compare August 30, 2026 16:44
@code-yeongyu
code-yeongyu force-pushed the fix/shared-host-extension-ui branch from 50a66cd to 67e6551 Compare August 30, 2026 17:03
@code-yeongyu
code-yeongyu enabled auto-merge August 30, 2026 17:18
@code-yeongyu
code-yeongyu merged commit 7ac3cf3 into main Aug 30, 2026
15 checks passed
@code-yeongyu
code-yeongyu deleted the fix/shared-host-extension-ui branch August 30, 2026 17:39
Sign up for free to 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.

1 participant