Skip to content

fix(packages/cli): dev server requires two Ctrl+C presses to exit #94

@zrosenbauer

Description

@zrosenbauer

Summary

The zpress dev server does not exit on the first Ctrl+C — it requires pressing Ctrl+C twice to terminate the process.

Current behavior

The dev server's only exit handler is inside the Ink TUI's useInput hook (packages/cli/src/screens/dev-screen.tsx:230-241):

useInput(
  (input, key) => {
    if (input === 'q' || (key.ctrl && input === 'c')) {
      if (watcherRef.current) {
        watcherRef.current.close()
      }
      exit()
      process.exit(0)
    }
  },
  { isActive: isTTY }
)

The dev command is registered with exit: 'manual' mode (packages/cli/src/commands/dev.ts), meaning the Kidd CLI framework expects the screen to handle its own exit. However, there is no process.on('SIGINT', ...) handler registered anywhere in the codebase.

When Ctrl+C is pressed:

  1. First press — The SIGINT signal is consumed by Ink's default handler, which begins a graceful unmount but does not terminate the process (manual exit mode). The useInput handler doesn't fire because the signal is intercepted at a lower level.
  2. Second press — Node's default SIGINT behavior force-terminates the process.

Expected behavior

A single Ctrl+C should gracefully shut down the dev server, close the file watcher, and exit the process.

Location

  • packages/cli/src/commands/dev.ts — dev command registration with exit: 'manual'
  • packages/cli/src/screens/dev-screen.tsx:230-241useInput exit handler (only TUI-level)
  • packages/cli/src/lib/watcher.ts:171-179 — watcher cleanup (close + cancel debounced syncs)
  • packages/cli/src/lib/rspress.ts:77-178 — Rspress dev server start/stop (no SIGINT handler)

Proposed approach

Register a process-level SIGINT handler that invokes the existing cleanup logic — close the file watcher, shut down the Rspress HTTP server, then process.exit(0). The cleanup code already exists; it just needs to be wired up to the signal.

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