| # bin/cli β OmniRoute CLI internals | |
| This directory contains the CLI runtime, helpers, and commands for the `omniroute` binary. | |
| ## Structure | |
| ``` | |
| bin/cli/ | |
| βββ CONVENTIONS.md β normative design rules (read this first) | |
| βββ README.md β this file | |
| βββ program.mjs β Commander setup β global flags, registerCommands() | |
| βββ api.mjs β apiFetch() β all HTTP calls + retry/backoff | |
| βββ runtime.mjs β withRuntime() β server-first / DB-fallback | |
| βββ i18n.mjs β t() β i18n helper + locale detection | |
| βββ output.mjs β emit() β table/json/jsonl/csv + printSuccess/printError | |
| βββ io.mjs β ask() / askSecret() β interactive prompts | |
| βββ data-dir.mjs β resolveDataDir() / resolveStoragePath() | |
| βββ sqlite.mjs β openOmniRouteDb() β DB bootstrap | |
| βββ encryption.mjs β encrypt/decrypt credentials | |
| βββ provider-catalog.mjs β static provider catalog | |
| βββ provider-store.mjs β DB CRUD for provider_connections | |
| βββ provider-test.mjs β testProviderApiKey() | |
| βββ settings-store.mjs β DB CRUD for key_value settings | |
| βββ locales/ | |
| β βββ en.json β English strings (source of truth, 42+ locales) | |
| β βββ pt-BR.json β Portuguese (Brazil) β fully translated | |
| β βββ {locale}.json β 40 additional locales (ar, az, de, es, fr, ja, zh-CN, β¦) | |
| βββ scripts/ | |
| β βββ generate-locales.mjs β scaffold new locale files from config/i18n.json | |
| βββ commands/ | |
| βββ setup.mjs | |
| βββ doctor.mjs | |
| βββ providers.mjs | |
| βββ config.mjs β includes `config lang get/set/list` | |
| βββ status.mjs | |
| βββ logs.mjs | |
| βββ update.mjs | |
| ``` | |
| ## Key helpers | |
| ### `apiFetch(path, opts)` β `api.mjs` | |
| All HTTP calls to the OmniRoute server must go through this wrapper. | |
| ```js | |
| import { apiFetch } from "./api.mjs"; | |
| const res = await apiFetch("/api/health"); | |
| if (!res.ok) await res.assertOk(); // throws ApiError with mapped exit code | |
| const data = await res.json(); | |
| ``` | |
| Options: | |
| - `baseUrl` β override base URL (default: `OMNIROUTE_BASE_URL` env or `localhost:20128`) | |
| - `apiKey` β override API key (default: `OMNIROUTE_API_KEY`) | |
| - `method`, `body`, `headers` β standard fetch options | |
| - `timeout` β per-attempt ms (default: `30000`) | |
| - `retry` β `false` to disable (default: enabled) | |
| - `retryMax` β total attempts (default: `3`) | |
| - `verbose` β log retry attempts to stderr | |
| ### `withRuntime(fn, opts)` β `runtime.mjs` | |
| Provides server-first / DB-fallback transparently. | |
| ```js | |
| import { withRuntime } from "./runtime.mjs"; | |
| await withRuntime(async (ctx) => { | |
| if (ctx.kind === "http") { | |
| const res = await ctx.api("/v1/providers"); | |
| return res.json(); | |
| } | |
| return ctx.db.prepare("SELECT * FROM provider_connections").all(); | |
| }); | |
| ``` | |
| - `opts.requireServer = true` β throws `ServerOfflineError` (exit 3) if offline | |
| - `opts.preferDb = true` β always use DB (skip server check) | |
| ### `t(key, vars)` β `i18n.mjs` | |
| Internationalized strings. Catalog loaded from `locales/{locale}.json`. | |
| ```js | |
| import { t } from "./i18n.mjs"; | |
| console.log(t("common.serverOffline")); | |
| console.log(t("setup.testFailed", { error: err.message })); | |
| ``` | |
| Locale detection order: `OMNIROUTE_LANG` β `LC_ALL` β `LC_MESSAGES` β `LANG` β `en`. | |
| ### `emit(data, opts)` β `output.mjs` | |
| Format-aware output. Reads `opts.output` to select table/json/jsonl/csv. | |
| ```js | |
| import { emit, printError, EXIT_CODES } from "./output.mjs"; | |
| emit(providers, { output: opts.output ?? "table" }); | |
| printError("Something went wrong"); | |
| process.exit(EXIT_CODES.SERVER_OFFLINE); | |
| ``` | |
| ## Locale selection | |
| The CLI displays text in the user's language. Detection order: | |
| 1. `--lang <code>` flag on the command line | |
| 2. `OMNIROUTE_LANG` environment variable | |
| 3. System env: `LC_ALL` β `LC_MESSAGES` β `LANG` | |
| 4. Fallback: `en` | |
| **Set permanently:** | |
| ```bash | |
| omniroute config lang set pt-BR # saves to ~/.omniroute/.env | |
| omniroute config lang list # show all 42 available locales | |
| omniroute config lang get # show currently active locale | |
| ``` | |
| **One-time override:** | |
| ```bash | |
| omniroute --lang de providers list # run in German, not persisted | |
| OMNIROUTE_LANG=ja omniroute status # same effect via env | |
| ``` | |
| **Adding a new locale**: add entry to `config/i18n.json`, then run: | |
| ```bash | |
| node bin/cli/scripts/generate-locales.mjs | |
| ``` | |
| ## Adding a new command | |
| 1. Create `bin/cli/commands/your-command.mjs` | |
| 2. Export `registerYourCommand(program)` following the Commander pattern | |
| 3. Register in `bin/cli/commands/registry.mjs` | |
| 4. Add strings to `locales/en.json` and `locales/pt-BR.json` | |
| 5. Write test in `tests/unit/cli-your-command.test.ts` | |
| See `CONVENTIONS.md` for exit codes, flag naming, output format, and destructive-action rules. | |