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
This commit is contained in:
Kao Félix 2026-02-07 15:55:08 +01:00 committed by GitHub
parent 828c40cf68
commit 6a3d6fe944
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 16 additions and 0 deletions

View file

@ -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);

View file

@ -175,6 +175,7 @@ const noOpUIContext: ExtensionUIContext = {
setHeader: () => {},
setTitle: () => {},
custom: async () => undefined as never,
pasteToEditor: () => {},
setEditorText: () => {},
getEditorText: () => "",
editor: async () => undefined,

View file

@ -162,6 +162,9 @@ export interface ExtensionUIContext {
},
): Promise<T>;
/** 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;

View file

@ -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),

View file

@ -197,6 +197,11 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
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({

View file

@ -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)
// =========================================================================