# TASK METADATA - **Target Files:** `infra/setup.ts` - **Core Objective:** Design a robust, non-interactive (headless) execution mode for `setup.ts` with explicit guardrails to prevent VM hangs. - **Dependencies:** `jsr:@cliffy/command` or similar argument parsing library integration may be required for the CLI subcommands. - **Additional Important Notes:** Must preserve the existing interactive menu when run without arguments in a TTY environment. Must fail-fast if headless environment is detected without explicit headless flags. --- ## 1. Input Audit The current interactive wizard in `setup.ts` requests the following inputs and configurations across its menus and sub-menus: ### A. Main Menu Actions (`Select.prompt`) The user is prompted to choose one of the following execution paths: - `[Test Hub Connection]` -> `test` - `[Configure Central Hub]` -> `hub` - `[Configure Auth Yes API]` -> `auth` - `[Compile Protobuf Definitions]` -> `compile_proto` - `[Review Generated Configs]` -> `review` - `[Build and Push Hub Image]` -> `build` - `[Build and Push Auth Yes Image]` -> `build_auth` - `[Generate Edge Handshake]` -> `handshake` - `[Exit]` -> `exit` ### B. Hub Setup (`handleHubSetup`) Requires the following inputs (`SetupConfig`): - **Container Registry URL** (`Input.prompt`): e.g., `quay.atyg.org` - **System Domain Name** (`Input.prompt`): e.g., `system.local` - **Database Path on Host** (`Input.prompt`): e.g., `/volume1/docker/ed-droid/db` - **PostgreSQL Password** (`Secret.prompt`): Hidden input, falls back to existing if left blank. - **UI Modules** (`Checkbox.prompt`): Multi-select options (`route`, `roi`, `exo`, `log`). ### C. Auth Setup (`handleAuthSetup`) Requires the following inputs (`AuthSetupConfig`): - **Container Registry URL** (`Input.prompt`): e.g., `quay.atyg.org` - **Auth Domain Name** (`Input.prompt`): e.g., `auth.system.local` - **Database Path on Host** (`Input.prompt`): e.g., `/volume1/docker/auth-yes/db` - **App Secret for IDP** (`Secret.prompt`): Minimum length 16. - **PostgreSQL Password** (`Secret.prompt`): Hidden input, falls back to existing if left blank. ## 2. Headless Architecture Proposal To support non-interactive environments (like CI/CD or automated VM provisioning) without sacrificing the existing developer experience, a **hybrid CLI Subcommand + Environment Variable approach** is recommended. ### A. Subcommand Routing The interactive "Main Menu" should be mapped to explicit CLI subcommands. For example: - `deno run -A setup.ts hub` (corresponds to `[Configure Central Hub]`) - `deno run -A setup.ts auth` (corresponds to `[Configure Auth Yes API]`) - `deno run -A setup.ts build` (corresponds to `[Build and Push Hub Image]`) ### B. Configuration Injection (Hybrid Approach) For subcommands that require configuration (like `hub` and `auth`), we should use a combination of CLI flags for non-sensitive data and environment variables for secrets. **Example for Hub Setup:** `deno run -A setup.ts hub --auto --registry="quay.atyg.org" --domain="system.local" --db-path="/var/lib/db" --modules="route,log"` _Secrets:_ The PostgreSQL password should be read from the environment (e.g., `POSTGRES_PASSWORD`), failing explicitly if it is not provided. **Example for Auth Setup:** `deno run -A setup.ts auth --auto --registry="quay.atyg.org" --domain="auth.system.local" --db-path="/var/lib/auth-db"` _Secrets:_ The PostgreSQL password and App Secret should be read from the environment (e.g., `POSTGRES_PASSWORD`, `APP_SECRET`), failing explicitly if not provided. ### C. Fallback to Interactive If `setup.ts` is executed without any subcommands or arguments (i.e., `deno run -A setup.ts`), the script should verify it is in a terminal (see Guardrails) and immediately launch the existing interactive `runSetupWizard()`. ## 3. Execution Guardrails To absolutely prevent the script from hanging headless VMs by accidentally blocking on a `prompt()`, we must implement strict, early-exit guardrails. 1. **Terminal Detection (`fail-fast`):** At the very beginning of execution, check `Deno.stdin.isTerminal()`. If it is `false` (meaning we are running headless/non-interactive), the script **must** inspect the provided arguments. If explicit headless subcommands or a flag like `--auto`/`--headless` are **not** present, the script must abort immediately with a non-zero exit code and a clear error message (e.g., `"Error: Non-interactive environment detected, but no explicit CLI subcommands or --auto flag were provided. Aborting to prevent hangs."`). 2. **Clean Exit on Help/Version:** By utilizing a robust CLI parsing library (like Cliffy's `Command`), flags such as `--help` or `--version` will be intercepted _before_ any application logic or wizard is initialized, ensuring a clean `exit(0)`. 3. **Strict Validation in Headless Mode:** When running a subcommand in headless mode (e.g., `setup.ts hub --auto`), the script must validate that _all_ required inputs (either via flags or environment variables) are present before proceeding. If any are missing, it must `throw` or `Deno.exit(1)` rather than falling back to an interactive prompt.