/** * Local shapes mirroring the host's terminal-UI contracts. * * This extension does not import the upstream terminal-UI library directly; * it declares structurally compatible local declarations for the subset of * the framework that its UI components consume: `Component` (interface), * `TUI` (interface), `Text` (class), and the text helpers `visibleWidth`, * `truncateToWidth`, `wrapTextWithAnsi`, `matchesKey`. * * The host continues to supply a runtime that uses the upstream package * internally. We deliberately do not reach into it — we only declare the * shapes our renderers (`AgentDashboard`, `ConversationViewer`, etc.) need, * and rely on TypeScript's structural compatibility so that the host's * factory callbacks accept our returned `Component` objects. Any extra * surface the host's runtime exposes (parent class features, overlay * hooks, etc.) is invisible from this module, which is the desired * narrow contract. * * Why this exists at all: * - Keeps the extension free of any runtime dependency on a third-party * git-hosted package whose version drift has historically broken CI. * - Sidesteps recurring type breakage when transitive copies of the * upstream package sit at different versions across the host's * dependency tree. * - Aligns with AGENTS.md rule #4: no direct imports of `@earendil-works/pi-*` * packages — only this local contract. * * If the host ever introduces a related symbol we need to consume, add it * here as a new local declaration, not as an import. */ /** * The host passes an object of this shape (and possibly more) as the * `tui` argument to our factory callbacks (e.g. `ctx.ui.custom(factory)`). * * We never construct one ourselves — we just declare what we read. */ export interface TUI { /** Trigger a re-render of the current frame. The host always provides this. */ requestRender(): void; /** Terminal size, in cells. */ terminal: { rows: number; columns: number; }; } /** * Any object we return from a `ctx.ui.custom(factory)` callback conforms to * this. The host's runtime calls `render(width)` synchronously to draw the * current frame, may call `handleInput(data)` for key events, and may call * `invalidate()` when the theme changes or a fresh render is needed (cached * renderers should drop their cache here). * * Mirrors the host's `Component` exactly, no more — TypeScript's structural * typing needs every REQUIRED member present on implementers in order for * `new Text(...)` / our agent-dashboard classes to be assignable to the * host's `Component` type at the boundary (e.g. `defineTool({ renderCall })`, * `registerMessageRenderer`). If you add an optional member here, you must * also have a no-op default on every class implementing this contract. */ export interface Component { /** Render the current frame as an array of pre-wrapped lines. One line per array element. */ render(width: number): string[]; /** Optional key-event handler. */ handleInput?(data: string): void; /** Optional: tell the framework whether this component owns key-release events (Kitty protocol). */ wantsKeyRelease?: boolean; /** Required: invalidate any cached rendering state. Called when theme changes or the framework needs a fresh render. */ invalidate(): void; } /** * Local `Text` shape — the contract the host expects for tools' * `renderCall` / `renderResult` returns, where the object is rendered as a * single multi-line block. * * Constructor accepts 1 or 3 args: `new Text(content)` or * `new Text(content, x, y)`. The x/y coordinates are accepted so existing * call sites compile unchanged but are otherwise unused. */ export declare class Text implements Component { readonly content: string; readonly x: number; readonly y: number; constructor(content: string, x?: number, y?: number); /** Render: split content on `\n` (collapsed with `fastTruncate` so we never * emit lines wider than `width`). */ render(width: number): string[]; /** Invalidate: `Text` doesn't cache, so this is a no-op. */ invalidate(): void; } /** * Helper to compute length of an ANSI CSI escape sequence at index i. * Valid sequences end with a letter (0x40-0x5A or 0x61-0x7A). * Returns the length of the sequence if valid, 0 otherwise. */ export declare function getAnsiSequenceLength(str: string, i: number): number; export declare function visibleWidth(str: string): number; export declare function truncateToWidth(text: string, maxWidth: number, ellipsis?: string, pad?: boolean): string; export declare function wrapTextWithAnsi(text: string, width: number): string[]; export declare function matchesKey(data: string, keyId: string): boolean; /** True when `data` matches any key id in `keyIds`. */ export declare function matchesAnyKey(data: string, keyIds: readonly string[]): boolean;