Skip to content

hub-ui-onboard: default terminal confirmation is unusable under Nuxt 5's nuxi #448

Open

Description

@antfubot

Summary

Since v1.2.5 (#445), the default onConfirm of @devframes/hub-ui-onboard (confirmInTerminal() on process.stdin) asks before each panel Install. It never installs without consent, but under Nuxt 5's CLI the developer often can't see the question, or can't answer it. #445 expected that "nuxi forks the dev server with an inherited stdin, so the default prompt is expected to work there". That is not what happens with @nuxt/cli-nightly 4.0.1.

What nuxi does

  • The first dev server runs inside the nuxi process. Restarts move it to a pre-warmed fork (ForkPool in @nuxt/cli-nightly/dist/dev-*.mjs).
  • In the interactive TUI (the default in a terminal of at least 40x10), the nuxi process holds stdin in raw mode for single-key shortcuts. It captures the dev server's logs, and forks get stdio: ['ignore', 'pipe', 'pipe', 'ipc'].
  • In plain mode (NUXT_TUI=plain, or a small terminal), the nuxi process reads stdin with a readline for line shortcuts (r, o, u, qr, y = copy URL, c, q, h). Forks inherit the TTY.

Reproduction

nuxi dev (Nuxt 5 nightly, @nuxt/cli-nightly 4.0.1) under a 120x40 PTY, on a project where @nuxt/devtools-onboard calls createOnboarding() without onConfirm. Install is triggered with a same-origin POST /__devtools/__onboard/install.

nuxi mode Dev server runs in What happens on Install
TUI, first boot nuxi process (stdin raw and flowing, owned by the TUI) DF9005 is folded into the TUI's log capture. The developer only sees "⚠ N warnings". The next keypress answers it as a raw chunk, so pressing w or l to read the warning refuses the install (403).
TUI, after any restart fork, stdin /dev/null DF9006, refused at once (403 in 23 ms). Install can never succeed after the first restart.
plain, first boot nuxi process Works, but y⏎ also runs nuxi's own y shortcut (copy server URL)
plain, after a restart fork that shares the TTY with the parent's readline The parent reads the line, so once('data') never fires. The POST and the shared asking promise stay open forever, and the panel stays on "Confirm in your terminal...".

Possible directions

  • When the input is a TTY that something else holds in raw mode (input.isRaw === true), refuse at once with a clear diagnostic. That beats letting an unrelated keypress answer a question nobody can see.
  • Don't leave a question that can never be answered open forever: for example, refuse after a bounded wait, so the panel shows messages.refused.
  • Fix the nuxi claim in the guide, and recommend that hosts whose CLI owns the terminal pass onConfirm (ideally something nuxi provides that routes the prompt through its TUI).

Downstream: nuxt/devtools#1126 upgrades to v1.2.5, keeps the default onConfirm (fails closed), and lists this as a known gap. refs nuxt/nuxt#36581

This issue was written with the help of an AI agent.

Activity

  1. antfubot commented on Oct 14, 2026

    @antfubot
    CollaboratorAuthor

    Update: nuxt/devtools#1126 no longer keeps the default. @nuxt/devtools-onboard now passes its own onConfirm: () => true behind a middleware that only lets through requests from this machine: a loopback socket and a local Host name. Other devices get 403. The terminal prompt under nuxi is still the problem described above for any host that relies on the default.

    Written with the help of an AI agent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions