From 1d5fd2356803311843554e40bf01d9c2ecef95dc Mon Sep 17 00:00:00 2001 From: Cristina Poncela Cubeiro <140309543+cristinaponcela@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:11:04 +0200 Subject: [PATCH] fix: theme in ui attach --- packages/orchestrator/src/attach-ui.ts | 17 +++++++++++++---- packages/orchestrator/src/handler.ts | 9 ++++++++- packages/orchestrator/src/ipc/protocol.ts | 7 ++++++- packages/orchestrator/src/supervisor.ts | 4 ++++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/orchestrator/src/attach-ui.ts b/packages/orchestrator/src/attach-ui.ts index 05c8a9d7..61eb41d3 100644 --- a/packages/orchestrator/src/attach-ui.ts +++ b/packages/orchestrator/src/attach-ui.ts @@ -6,8 +6,6 @@ import type { RpcExtensionUIResponse, } from "@earendil-works/pi-coding-agent"; -import { theme } from "../../coding-agent/src/modes/interactive/theme/theme.ts"; - type DialogRequest = | Extract | Extract @@ -24,6 +22,7 @@ interface PendingExtensionRequest { export class AttachUiBridge { private readonly pendingRequests = new Map(); private onRequest?: (request: RpcExtensionUIRequest) => void; + private themeOverride?: unknown; attach(onRequest: (request: RpcExtensionUIRequest) => void): () => void { this.onRequest = onRequest; @@ -34,6 +33,13 @@ export class AttachUiBridge { }; } + setThemeOverride(theme: unknown): void { + // This comes from attach host context over JSONL IPC. Pi's Theme is a runtime class, + // not a wire-safe protocol type, so this remains opaque until we define a proper + // serializable theme snapshot/DTO for the attach protocol. + this.themeOverride = theme; + } + handleResponse(response: RpcExtensionUIResponse): void { const pending = this.pendingRequests.get(response.id); if (!pending) { @@ -44,6 +50,7 @@ export class AttachUiBridge { } createUiContext(): ExtensionUIContext { + const uiBridge = this; const requestDialog = ( request: DialogRequest, fallbackValue: T, @@ -154,8 +161,10 @@ export class AttachUiBridge { addAutocompleteProvider: () => {}, setEditorComponent: () => {}, getEditorComponent: () => undefined, - get theme() { - return theme; + get theme(): ExtensionUIContext["theme"] { + // If the attach host provides a theme object, forward it. Otherwise attach mode + // still has no real TUI/theme runtime, so fall back to an empty placeholder. + return (uiBridge.themeOverride ?? {}) as ExtensionUIContext["theme"]; }, getAllThemes: () => [], getTheme: () => undefined, diff --git a/packages/orchestrator/src/handler.ts b/packages/orchestrator/src/handler.ts index efcfb104..7d1c8ab3 100644 --- a/packages/orchestrator/src/handler.ts +++ b/packages/orchestrator/src/handler.ts @@ -5,6 +5,7 @@ import type { RpcExtensionUIResponse, } from "@earendil-works/pi-coding-agent"; import type { + AttachHostContextRequest, AttachReadyResponse, AttachRequest, AttachRpcResponse, @@ -136,7 +137,9 @@ export function attachIpcInstance( onUiRequest: (request: RpcExtensionUIRequest) => void, ): | { - handleRequest(request: { type: "attach_rpc"; command: RpcCommand } | RpcExtensionUIResponse): Promise; + handleRequest( + request: { type: "attach_rpc"; command: RpcCommand } | AttachHostContextRequest | RpcExtensionUIResponse, + ): Promise; close(): void; } | undefined { @@ -152,6 +155,10 @@ export function attachIpcInstance( onResponse({ type: "attach_rpc_result", response }); return; } + if (request.type === "attach_host_context") { + handle.setHostTheme(request.theme); + return; + } handle.handleUiResponse(request); }, close(): void { diff --git a/packages/orchestrator/src/ipc/protocol.ts b/packages/orchestrator/src/ipc/protocol.ts index 43929a71..1f4040a0 100644 --- a/packages/orchestrator/src/ipc/protocol.ts +++ b/packages/orchestrator/src/ipc/protocol.ts @@ -45,6 +45,11 @@ export interface AttachRpcRequest { command: RpcCommand; } +export interface AttachHostContextRequest { + type: "attach_host_context"; + theme?: unknown; +} + export interface RequestMap { spawn: SpawnRequest; list: ListRequest; @@ -127,7 +132,7 @@ export interface ResponseMap { } export type OrchestratorResponse = ResponseMap[keyof ResponseMap] | ErrorResponse; -export type AttachClientRequest = AttachRpcRequest | RpcExtensionUIResponse; +export type AttachClientRequest = AttachRpcRequest | AttachHostContextRequest | RpcExtensionUIResponse; export type AttachServerResponse = | AttachReadyResponse | AttachEventResponse diff --git a/packages/orchestrator/src/supervisor.ts b/packages/orchestrator/src/supervisor.ts index 886cbf26..24dddfbd 100644 --- a/packages/orchestrator/src/supervisor.ts +++ b/packages/orchestrator/src/supervisor.ts @@ -104,6 +104,7 @@ export class OrchestratorSupervisor { | { handleRpc(command: RpcCommand): Promise; handleUiResponse(response: RpcExtensionUIResponse): void; + setHostTheme(theme: unknown): void; close(): void; } | undefined { @@ -122,6 +123,9 @@ export class OrchestratorSupervisor { handleUiResponse: (response) => { live.uiBridge.handleResponse(response); }, + setHostTheme: (theme) => { + live.uiBridge.setThemeOverride(theme); + }, close: () => { detachUi(); live.subscribers.delete(onEvent);