From 6a3d6fe94465557360e6043a8fb54a186943c997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kao=20F=C3=A9lix?= Date: Sat, 7 Feb 2026 15:55:08 +0100 Subject: [PATCH] feat(tui, coding-agent): add pasteToEditor to ExtensionUIContext (#1351) Add pasteToEditor(text) method that pastes text into the editor via bracketed paste sequences, triggering paste handling (including collapse for large content). Unlike setEditorText which directly replaces content, pasteToEditor routes through handleInput on the active editor component. - Add pasteToEditor to ExtensionUIContext interface - Add handleInput to EditorComponent interface (was missing, all concrete implementations already had it) - Implement in interactive mode via bracketed paste sequence - Add fallback in RPC mode (delegates to setEditorText) - Document in extensions.md --- packages/coding-agent/docs/extensions.md | 3 +++ packages/coding-agent/src/core/extensions/runner.ts | 1 + packages/coding-agent/src/core/extensions/types.ts | 3 +++ .../coding-agent/src/modes/interactive/interactive-mode.ts | 1 + packages/coding-agent/src/modes/rpc/rpc-mode.ts | 5 +++++ packages/tui/src/editor-component.ts | 3 +++ 6 files changed, 16 insertions(+) diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index 332ce755..09cae0a8 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -1556,6 +1556,9 @@ ctx.ui.setTitle("pi - my-project"); ctx.ui.setEditorText("Prefill text"); const current = ctx.ui.getEditorText(); +// Paste into editor (triggers paste handling, including collapse for large content) +ctx.ui.pasteToEditor("pasted content"); + // Tool output expansion const wasExpanded = ctx.ui.getToolsExpanded(); ctx.ui.setToolsExpanded(true); diff --git a/packages/coding-agent/src/core/extensions/runner.ts b/packages/coding-agent/src/core/extensions/runner.ts index 4b69c6eb..44bb323e 100644 --- a/packages/coding-agent/src/core/extensions/runner.ts +++ b/packages/coding-agent/src/core/extensions/runner.ts @@ -175,6 +175,7 @@ const noOpUIContext: ExtensionUIContext = { setHeader: () => {}, setTitle: () => {}, custom: async () => undefined as never, + pasteToEditor: () => {}, setEditorText: () => {}, getEditorText: () => "", editor: async () => undefined, diff --git a/packages/coding-agent/src/core/extensions/types.ts b/packages/coding-agent/src/core/extensions/types.ts index 45bf4806..4362b6af 100644 --- a/packages/coding-agent/src/core/extensions/types.ts +++ b/packages/coding-agent/src/core/extensions/types.ts @@ -162,6 +162,9 @@ export interface ExtensionUIContext { }, ): Promise; + /** Paste text into the editor, triggering paste handling (collapse for large content). */ + pasteToEditor(text: string): void; + /** Set the text in the core input editor. */ setEditorText(text: string): void; diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 2d7207f1..b325c59e 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -1383,6 +1383,7 @@ export class InteractiveMode { setHeader: (factory) => this.setExtensionHeader(factory), setTitle: (title) => this.ui.terminal.setTitle(title), custom: (factory, options) => this.showExtensionCustom(factory, options), + pasteToEditor: (text) => this.editor.handleInput(`\x1b[200~${text}\x1b[201~`), setEditorText: (text) => this.editor.setText(text), getEditorText: () => this.editor.getText(), editor: (title, prefill) => this.showExtensionEditor(title, prefill), diff --git a/packages/coding-agent/src/modes/rpc/rpc-mode.ts b/packages/coding-agent/src/modes/rpc/rpc-mode.ts index 78b9849e..4ab920ce 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-mode.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-mode.ts @@ -197,6 +197,11 @@ export async function runRpcMode(session: AgentSession): Promise { return undefined as never; }, + pasteToEditor(text: string): void { + // Paste handling not supported in RPC mode - falls back to setEditorText + this.setEditorText(text); + }, + setEditorText(text: string): void { // Fire and forget - host can implement editor control output({ diff --git a/packages/tui/src/editor-component.ts b/packages/tui/src/editor-component.ts index 87ec9581..c6b6c43d 100644 --- a/packages/tui/src/editor-component.ts +++ b/packages/tui/src/editor-component.ts @@ -19,6 +19,9 @@ export interface EditorComponent extends Component { /** Set the text content */ setText(text: string): void; + /** Handle raw terminal input (key presses, paste sequences, etc.) */ + handleInput(data: string): void; + // ========================================================================= // Callbacks (required) // =========================================================================