watchForInput method

void watchForInput()

Implementation

void watchForInput() {
  try {
    // Create broadcast stream controller once from stdin. Headless / AI
    // launches often get an immediately-closed stdin — do not poison the
    // controller permanently when that happens.
    if (_stdinController == null || _stdinController!.isClosed) {
      _stdinController = StreamController<List<int>>.broadcast();
      _stdinSourceSubscription?.cancel();
      _stdinSourceSubscription = io.stdin.listen(
        (event) => _stdinController?.add(event),
        onDone: () {
          logger.detail('stdin closed; hotkeys unavailable until restart');
          _stdinSourceSubscription = null;
        },
        onError: (Object e) {
          logger.detail('stdin error: $e');
        },
        cancelOnError: false,
      );
    }

    // Cancel existing subscription if any
    _inputSubscription?.cancel();

    // Re-lock input to ensure single-key mode is maintained
    lockInput();

    _inputSubscription = _stdinController?.stream.listen((event) {
      _handleDevCommand(utf8.decode(event));
    });
  } catch (e) {
    logger
      ..detail('stdin not available (headless/AI mode): $e')
      ..detail('Use .revali_cmd file for r/c/q commands instead');
  }

  logger.detail('Watching for kill signal');

  var attemptsToKill = 0;
  final stream = Platform.isWindows
      ? ProcessSignal.sigint.watch()
      : StreamGroup.merge([
          ProcessSignal.sigterm.watch(),
          ProcessSignal.sigint.watch(),
        ]);

  _killSubscription ??= stream.listen((event) {
    // Killing the child during hot-reload restart must not tear down the
    // parent CLI (signals can surface here when the child shares a group).
    if (_intentionalServerRestart || _isReloading) {
      logger.detail('Ignoring $event during reload/restart');
      return;
    }

    logger.detail('Received process signal: $event');
    if (attemptsToKill > 0) {
      logger.detail('Second signal received, forcing exit');
      exit(1);
    } else if (attemptsToKill == 0) {
      logger.detail('Gracefully shutting down (user requested)');
      stop().ignore();
    }

    attemptsToKill++;
  });
}