Files
OmniRoute/bin/cli
Xiangzhe 6fb444ef64 fix(build): align pack-boot sql.js expectations with dependency-based packaging (#11242)
check:pack-artifact and check:pack-boot have been self-contradictory since
05/08, blocking the v3.8.50 publish in ci.yml (build:cli job) and
npm-publish.yml:

- check:pack-artifact FAILS any tarball path containing a node_modules
  segment (PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS; files[] also excludes
  "!**/node_modules/**").
- check:pack-boot REQUIRED sql.js under the vendored
  dist/node_modules/sql.js location — a path the tarball can never carry,
  so both gates could never be green at once.

The packaging model is now dependency-based: sql.js and node-machine-id
are declared `dependencies` (a clean install places them under
<packageRoot>/node_modules/), and better-sqlite3 is an optionalDependency
installed natively per platform (^13.0.2 — which also covers the
darwin-arm64 prebuild gap from #11242 by construction). The runtime
already resolves the WASM at <cwd>/node_modules/sql.js/dist/sql-wasm.wasm
(src/lib/db/adapters/sqljsAdapter.ts).

Changes:
- scripts/check/check-pack-boot.mjs: REQUIRED_SQLJS_RUNTIME_FILES now
  points at node_modules/sql.js/{package.json,dist/sql-wasm.js,
  dist/sql-wasm.wasm} — the dependency-installed location the clean-prefix
  install actually produces. REQUIRED_MACHINE_TOKEN_RUNTIME_FILES was
  already correct and is unchanged.
- bin/cli/runtime/sqliteRuntime.mjs: BETTER_SQLITE3_VERSION bumped
  ^12.10.1 -> ^13.0.2 to match optionalDependencies (the lazy runtime
  install was pulling the wrong major), and exported for the guard.
- tests/unit/pack-boot-runtime-paths.test.ts (new, TDD: RED -> GREEN):
  pins that (a) no pack-boot required path references a never-publishable
  vendored dist/<segment> location (driven by
  PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS), (b) sql.js/node-machine-id stay
  declared dependencies, (c) the lazy-install spec stays on the declared
  optionalDependency major.
- tests/unit/check-pack-boot.test.ts: the sql.js contract test pinned the
  old vendored path; updated to node_modules/sql.js/dist/sql-wasm.wasm.
  This is alignment to the real new contract (vendoring ended), not
  masking — the same test still asserts the find-missing behavior.

Electron is unaffected: the vendored dist/node_modules bundle still
exists for Electron packaging (postinstall.mjs and assembleStandalone.mjs
untouched).

Refs #11242
Refs #10296
2026-08-23 13:13:32 -03:00
..
2026-06-23 03:08:29 -03:00
2026-05-21 01:29:12 -03:00
2026-06-21 08:56:51 -03:00
2026-05-10 00:55:06 -03:00
2026-05-10 00:55:06 -03:00

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, 43 locales)
│   ├── pt-BR.json          ← Portuguese (Brazil) — fully translated
│   └── {locale}.json       ← 42 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.

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)
  • retryfalse 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.

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.

import { t } from "./i18n.mjs";

console.log(t("common.serverOffline"));
console.log(t("setup.testFailed", { error: err.message }));

Locale detection order: OMNIROUTE_LANGLC_ALLLC_MESSAGESLANGen.

emit(data, opts)output.mjs

Format-aware output. Reads opts.output to select table/json/jsonl/csv.

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_ALLLC_MESSAGESLANG
  4. Fallback: en

Set permanently:

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:

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:

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.