diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c1a5d4e56..242c8b162 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -9,6 +9,7 @@ - npm installs now execute a prebundled single-file entry: `bin.omp` points at `dist/cli.js` (built by `scripts/bundle-dist.ts` during `prepack`, ~18MB minified, natives/transformers/mupdf external), cutting npm-install cold start by roughly 3x versus transpiling the raw TypeScript graph per launch; `src/**` stays published for SDK consumers and worker fallbacks - Plain interactive TTY launches print a dim two-line startup splash (`omp ` / `Initializing session…`) before session construction so first pixels appear immediately; suppressed for resume/fork/continue flows, quiet mode, `PI_TIMING`, and non-TTY stdio - Added `/stats` to launch the local stats dashboard from an active session, syncing session files first and opening the same browser dashboard as `omp stats`. +- `/settings` now supports type-to-search filtering on setting labels, paths, descriptions, and values; Escape clears an active search before closing the panel. ### Changed @@ -42,6 +43,7 @@ ### Fixed +- Fixed pasting into the ask tool's "Other (type your own)" text box (and hook input/editor dialogs) on terminals with OSC 5522 enhanced paste (kitty protocol): the enhanced-paste focus routing only targets components exposing a `pasteText` hook, and the dialog wrappers had none, so the payload was stuffed into the main prompt editor hidden behind the dialog. `HookEditorComponent` and `HookInputComponent` now forward `pasteText` to their inner editor/input (pasting also resets the input dialog's timeout countdown like any keystroke). - Fixed auto-retry giving up after one attempt ("Provider requested Xms wait, exceeds retry.maxDelayMs") on a usage-limit 429 when every sibling account was only momentarily blocked: the retry delay now waits for the earliest sibling unblock when that comes sooner than the provider's multi-hour retry-after, so the next attempt picks up the recovered account instead of failing fast. - Fixed Hindsight `per-project-tagged` mental-model seeding so each project gets its own conventions/decisions models and session context only injects active-project or untagged models ([#2218](https://github.com/can1357/oh-my-pi/issues/2218)). diff --git a/packages/coding-agent/src/modes/components/hook-editor.ts b/packages/coding-agent/src/modes/components/hook-editor.ts index fe0de86a0..6fe845fd9 100644 --- a/packages/coding-agent/src/modes/components/hook-editor.ts +++ b/packages/coding-agent/src/modes/components/hook-editor.ts @@ -86,6 +86,14 @@ export class HookEditorComponent extends Container { this.#onSubmitCallback(this.#editor.getExpandedText()); } + /** Route non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard) + * into the inner editor, mirroring bracketed-paste semantics. Without this hook, + * enhanced-paste routing falls back to the main prompt editor hidden behind the + * dialog (#2127 routing contract). */ + pasteText(text: string): void { + this.#editor.pasteText(text); + } + /** Prompt-style: raw Enter submits; Editor owns newline-producing sequences. */ #handlePromptStyleInput(keyData: string): void { // Prompt-style keeps Escape as an explicit cancel key and also honors app.interrupt remaps. diff --git a/packages/coding-agent/src/modes/components/hook-input.ts b/packages/coding-agent/src/modes/components/hook-input.ts index 7a42ecde1..e1fc3a930 100644 --- a/packages/coding-agent/src/modes/components/hook-input.ts +++ b/packages/coding-agent/src/modes/components/hook-input.ts @@ -73,6 +73,14 @@ export class HookInputComponent extends Container { } } + /** Route non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard) + * into the inner input, mirroring bracketed-paste semantics. Pasting counts as + * interaction, so the timeout countdown resets like any keystroke. */ + pasteText(text: string): void { + this.#countdown?.reset(); + this.#input.pasteText(text); + } + dispose(): void { this.#countdown?.dispose(); } diff --git a/packages/coding-agent/test/hook-editor.test.ts b/packages/coding-agent/test/hook-editor.test.ts index 0e3eb5019..a5316b722 100644 --- a/packages/coding-agent/test/hook-editor.test.ts +++ b/packages/coding-agent/test/hook-editor.test.ts @@ -218,6 +218,29 @@ describe("HookEditorComponent prompt-style mode", () => { expect(onCancel).not.toHaveBeenCalled(); }); + it("absorbs enhanced-paste payloads delivered via pasteText (kitty OSC 5522 routing)", () => { + // Regression: pasting into the ask tool's "Other" editor on OSC 5522 + // terminals routed the payload to the hidden main prompt, because the + // enhanced-paste focus routing only targets components exposing a + // `pasteText` hook and the dialog wrapper had none (#2127 contract). + const onSubmit = vi.fn(); + const onCancel = vi.fn(); + const component = new HookEditorComponent(createTui(), "Prompt", undefined, onSubmit, onCancel, { + promptStyle: true, + }); + const pasted = largePasteText(); + + component.pasteText(pasted); + + expect(renderText(component)).toContain("[Paste #1, +11 lines]"); + + component.handleInput("\r"); + + expect(onSubmit).toHaveBeenCalledTimes(1); + expect(onSubmit).toHaveBeenCalledWith(pasted); + expect(onCancel).not.toHaveBeenCalled(); + }); + it("expands large paste markers when submitting on Enter", () => { const onSubmit = vi.fn(); const onCancel = vi.fn(); diff --git a/packages/coding-agent/test/hook-input-timeout.test.ts b/packages/coding-agent/test/hook-input-timeout.test.ts index f35775a06..532800af4 100644 --- a/packages/coding-agent/test/hook-input-timeout.test.ts +++ b/packages/coding-agent/test/hook-input-timeout.test.ts @@ -72,4 +72,36 @@ describe("HookInputComponent timeout", () => { component.dispose(); }); + + it("absorbs enhanced-paste payloads via pasteText and resets the timeout", () => { + // Regression: enhanced-paste (kitty OSC 5522) focus routing only targets + // components exposing a `pasteText` hook; without one the payload landed + // in the hidden main prompt behind the dialog (#2127 contract). + vi.useFakeTimers(); + + const onSubmit = vi.fn(); + const onCancel = vi.fn(); + const onTimeout = vi.fn(); + const tui = { requestRender: vi.fn() } as unknown as TUI; + + const component = new HookInputComponent("Prompt", undefined, onSubmit, onCancel, { + timeout: 1_000, + tui, + onTimeout, + }); + + vi.advanceTimersByTime(900); + component.pasteText("sk-line1\nsk-line2"); + + vi.advanceTimersByTime(900); + expect(onTimeout).not.toHaveBeenCalled(); + expect(onCancel).not.toHaveBeenCalled(); + + component.handleInput("\n"); + + expect(onSubmit).toHaveBeenCalledTimes(1); + expect(onSubmit).toHaveBeenCalledWith("sk-line1sk-line2"); + + component.dispose(); + }); });