Commit graph

3 commits

Author SHA1 Message Date
robopipi[bot]
c1810bf70f
feat(coding-agent): let inline ctx.ui.custom() components report blocked program status (#11471)
Inline `ctx.ui.custom()` components never report pi as blocked through
OSC 7501 program status. This is on purpose, because the same API hosts
loaders. As a result, a custom dialog that waits for the user (an
approval prompt, the `question.ts` example) shows up as `working`, and
the terminal cannot tell that pi needs input.

The extension dialog stack already stores a blocked status for each
dialog and reports the visible one. This change adds an optional
`blocked` option to `ctx.ui.custom()`:

```ts
ctx.ui.custom(factory, { blocked: { kind: "question", message: "Pick a color" } });
```

The inline branch of `showExtensionCustom()` passes it to
`pushExtensionDialog()`. Components without the option behave as before.
Overlays ignore the option because they are not part of the dialog
stack. `docs/tui.md` documents the option.

Testing:
- Added a test to `test/interactive-mode-extension-dialogs.test.ts`:
  - A custom component that opts in reports `blocked`.
- A plain custom component stacked on top of it clears the blocked
status.
  - Closing the plain component restores the blocked status.
  - Closing the opted-in component clears it.
- The test fails without the change to `interactive-mode.ts` and passes
with it.
- `npm run check`: biome and lint pass, and there are no type errors in
coding-agent. The only errors are existing type errors in
`packages/ai/test` from locally generated model data. They are not
related to this change.

Fixes #11428

Requested by @badlogic

Co-authored-by: triagent <triagent@localhost>
2026-10-27 09:27:28 +01:00
robopipi[bot]
7853186d14
fix(coding-agent): keep open extension dialog visible when the editor component is replaced (#11466)
`ctx.ui.setEditorComponent()` always cleared the editor slot and put the
new editor there with focus. If an extension dialog
(`confirm`/`select`/`input`/`editor`, or an inline `custom()` component)
was open at that moment, the editor replaced it on screen. The dialog
was still on the dialog stack and its promise still pending, but nobody
could see or answer it. It hung until its timeout, or forever without
one.

Now `setCustomEditorComponent` leaves the editor slot and focus alone
while a dialog is open. The new editor is still created and wired up,
and `showTopExtensionDialog` shows it when the last dialog closes.
Without an open dialog nothing changes.

Testing:
- Added a regression test to
`test/interactive-mode-extension-dialogs.test.ts`. It opens a confirm,
replaces the editor, then checks that the confirm stays visible and
answerable and that the new editor is focused afterwards. It fails
without the fix and passes with it.
- `npm run check` passes.
- Ran the reproduction from the issue in tmux (`pi -e ./a.ts -e ./b.ts`,
where a.ts opens a non-blocking `confirm` in `session_start` and b.ts
calls `setEditorComponent`).
  - Before: only the editor shows, and the confirm times out.
  - After: the confirm shows, and Enter gives `answer: true`.

Fixes #11431

Requested by @badlogic

Co-authored-by: triagent <triagent@localhost>
2026-10-27 09:11:18 +01:00
Mario Zechner
38847563f4 fix(coding-agent): stack concurrent extension dialogs instead of replacing them
A second select/confirm/input/editor dialog or inline custom() component
replaced the visible one and left its promise pending forever. Dialogs in
the editor slot now form a stack: closing the visible dialog shows the
previous one again, and dialogs opened from inside a custom component work.

closes #11166
2026-10-20 20:45:12 +02:00