runIdeApp function

Future<void> runIdeApp({
  1. required Workspace workspace,
  2. Stream<List<int>>? input,
  3. ShellFamily? shellFamily,
  4. TerminalDriver? terminal,
  5. AiConfig? loadAiConfig()?,
})

Builds and runs the full-screen IdeApp over workspace, returning when the user quits it.

Shared by the in-session :ide command and the standalone omnyshell ide CLI command, so both get the same AI agent and command-gating wiring: the panel is wired to the provider configured via the environment / ai.yaml (when none is configured it shows setup help instead), and the agent's run_command tool is gated by the same command_shield used by :ai.

input is the host's forwarded stdin, for embedders that already own the single stdin subscription (the interactive shell's line editor). Leave it null — as the standalone CLI command does — to let Terminal read stdin itself. shellFamily selects the syntax the agent validates its commands against.

terminal replaces the real Terminal and loadAiConfig replaces AiConfigIo.load, so tests neither take over the TTY nor read the user's AI settings.

Implementation

Future<void> runIdeApp({
  required Workspace workspace,
  Stream<List<int>>? input,
  ShellFamily? shellFamily,
  TerminalDriver? terminal,
  AiConfig? Function()? loadAiConfig,
}) async {
  final aiConfig = loadAiConfig != null ? loadAiConfig() : AiConfigIo.load();
  final aiProvider = aiConfig == null
      ? null
      : providerFor(aiConfig, http.Client());
  final shield = CommandShield(
    analyzer: Analyzer(
      securityAnalyzer: SecurityAnalyzer(
        detectors: [
          ...SecurityAnalyzer.defaultDetectors,
          KnowledgeRiskDetector(),
        ],
      ),
    ),
  );
  final app = IdeApp(
    workspace: workspace,
    terminal: terminal ?? Terminal(inputOverride: input),
    aiProvider: aiProvider,
    aiModel: aiConfig?.model,
    shield: shield,
    commandSyntax: ideCommandSyntaxFor(shellFamily),
  );
  await app.run();
}