diff --git a/README.md b/README.md index b6c411fd289c..c73c8f934a4b 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,7 @@ omniroute connect 192.168.0.15 # password → scoped token, saved as omniroute models list # ← runs against the REMOTE server omniroute configure codex # ← picks a remote model, writes a local Codex profile omniroute tokens create --name ci --scope read # mint narrower tokens for other machines +omniroute contexts use default # ← switch back to the local server ``` Tokens are scoped `read` / `write` / `admin`; process-spawning routes stay loopback-only. diff --git a/bin/cli/commands/contexts.mjs b/bin/cli/commands/contexts.mjs index 00f565ed969c..2057f051b7c7 100644 --- a/bin/cli/commands/contexts.mjs +++ b/bin/cli/commands/contexts.mjs @@ -9,7 +9,15 @@ function authLabel(c) { return "✗"; } -async function confirm(msg) { +export async function confirm(msg) { + // Non-interactive stdin (pipe, CI, EOF) cannot answer a [y/N] prompt. Asking + // anyway leaves the readline question pending forever — Node then warns about an + // "unsettled top-level await" at exit. Decline cleanly instead and point at the + // non-interactive escape hatch so scripted callers fail safe rather than hang. + if (!process.stdin.isTTY) { + process.stderr.write(`${msg} [y/N] (non-interactive stdin — declined; pass --yes to confirm)\n`); + return false; + } const readline = await import("node:readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const answer = await new Promise((r) => rl.question(`${msg} [y/N] `, r)); diff --git a/docs/guides/REMOTE-MODE.md b/docs/guides/REMOTE-MODE.md index ab1cd097fe93..d593b3d78fdf 100644 --- a/docs/guides/REMOTE-MODE.md +++ b/docs/guides/REMOTE-MODE.md @@ -172,12 +172,60 @@ opencode -m omniroute/glm/glm-5.2 "..." # export OMNIROUTE_API_KEY firs --- -## Switching back to local +## Managing contexts (switch between servers) + +A **context** is a saved server (baseUrl + credential + scope). `omniroute connect` +creates one and makes it active; from then on every command targets it. Manage and +switch between them with `omniroute contexts`: + +```bash +omniroute contexts list # all contexts; the active one is marked ● +omniroute contexts current # the active server, auth status, scope +``` + +```text + | Name | Base URL | Auth | Scope | Description +● | vps | http://100.67.86.91:20128 | token | admin | Remote OmniRoute (…) + | default | http://localhost:20128 | ✗ | | +``` + +**Switch servers** — every subsequent command follows the active context: + +```bash +omniroute contexts use vps # → all commands now hit the remote VPS +omniroute tokens list # (runs against the VPS) + +omniroute contexts use default # → back to localhost +omniroute tokens list # (runs against the local server) +``` + +**Add a context manually** (instead of `connect`), inspect, or rename: + +```bash +omniroute contexts add staging --url https://staging.example.com:20128 \ + --access-token oma_live_xxxx --scope write --description "staging box" +omniroute contexts show staging # full details for one context +omniroute contexts rename staging stg +``` + +**Remove a context** — prompts for confirmation; pass `--yes` to skip it +(required for scripts / non-interactive shells, which otherwise decline safely): + +```bash +omniroute contexts remove stg --yes +``` + +> `default` (localhost) cannot be removed. Removing the active context falls back +> to `default`. Tip: removing a context only drops the **local** saved credential — +> revoke the token on the server with `omniroute tokens revoke ` to actually +> kill access. + +**Export / import** contexts (e.g. to move them between machines — secrets included, +so handle the file carefully): ```bash -omniroute contexts use default # back to localhost -omniroute context current # show active server, auth, scope -omniroute contexts list # all contexts +omniroute contexts export --out contexts.json # default: stdout +omniroute contexts import contexts.json # overwrite; --merge to keep existing ``` --- diff --git a/docs/i18n/ar/CHANGELOG.md b/docs/i18n/ar/CHANGELOG.md index b0cb5284d1e8..408d293c441d 100644 --- a/docs/i18n/ar/CHANGELOG.md +++ b/docs/i18n/ar/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/az/CHANGELOG.md b/docs/i18n/az/CHANGELOG.md index 33fda4af262e..62f1ba31c5b0 100644 --- a/docs/i18n/az/CHANGELOG.md +++ b/docs/i18n/az/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/bg/CHANGELOG.md b/docs/i18n/bg/CHANGELOG.md index 33fda4af262e..62f1ba31c5b0 100644 --- a/docs/i18n/bg/CHANGELOG.md +++ b/docs/i18n/bg/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/bn/CHANGELOG.md b/docs/i18n/bn/CHANGELOG.md index c2efef419470..4d72ba3d4f5f 100644 --- a/docs/i18n/bn/CHANGELOG.md +++ b/docs/i18n/bn/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/cs/CHANGELOG.md b/docs/i18n/cs/CHANGELOG.md index b12596b440d6..b8f3fb60daab 100644 --- a/docs/i18n/cs/CHANGELOG.md +++ b/docs/i18n/cs/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/da/CHANGELOG.md b/docs/i18n/da/CHANGELOG.md index ab3d956150aa..70e74b7340c5 100644 --- a/docs/i18n/da/CHANGELOG.md +++ b/docs/i18n/da/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/de/CHANGELOG.md b/docs/i18n/de/CHANGELOG.md index c6c8b1e4bee7..ba13e5413384 100644 --- a/docs/i18n/de/CHANGELOG.md +++ b/docs/i18n/de/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/es/CHANGELOG.md b/docs/i18n/es/CHANGELOG.md index ec9bf4429fe8..cd89958279ca 100644 --- a/docs/i18n/es/CHANGELOG.md +++ b/docs/i18n/es/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/fa/CHANGELOG.md b/docs/i18n/fa/CHANGELOG.md index 168467842dd9..cb4ceeb844ed 100644 --- a/docs/i18n/fa/CHANGELOG.md +++ b/docs/i18n/fa/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/fi/CHANGELOG.md b/docs/i18n/fi/CHANGELOG.md index 767e34e11773..b5718aa5c104 100644 --- a/docs/i18n/fi/CHANGELOG.md +++ b/docs/i18n/fi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/fr/CHANGELOG.md b/docs/i18n/fr/CHANGELOG.md index 51217cdf71e7..d8a768b671f7 100644 --- a/docs/i18n/fr/CHANGELOG.md +++ b/docs/i18n/fr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/gu/CHANGELOG.md b/docs/i18n/gu/CHANGELOG.md index 29cbc81a6920..25faba924154 100644 --- a/docs/i18n/gu/CHANGELOG.md +++ b/docs/i18n/gu/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/he/CHANGELOG.md b/docs/i18n/he/CHANGELOG.md index 732adee25199..79f8697a128f 100644 --- a/docs/i18n/he/CHANGELOG.md +++ b/docs/i18n/he/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/hi/CHANGELOG.md b/docs/i18n/hi/CHANGELOG.md index 9850144284e3..43c8369a4014 100644 --- a/docs/i18n/hi/CHANGELOG.md +++ b/docs/i18n/hi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/hu/CHANGELOG.md b/docs/i18n/hu/CHANGELOG.md index 5c8a02f0dc4d..f3b0fbf18f9c 100644 --- a/docs/i18n/hu/CHANGELOG.md +++ b/docs/i18n/hu/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/id/CHANGELOG.md b/docs/i18n/id/CHANGELOG.md index 334171bcb053..fe89bae0297f 100644 --- a/docs/i18n/id/CHANGELOG.md +++ b/docs/i18n/id/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/in/CHANGELOG.md b/docs/i18n/in/CHANGELOG.md index 813ea2565349..9983b842640a 100644 --- a/docs/i18n/in/CHANGELOG.md +++ b/docs/i18n/in/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/it/CHANGELOG.md b/docs/i18n/it/CHANGELOG.md index d650a7af3680..a245dfa92e20 100644 --- a/docs/i18n/it/CHANGELOG.md +++ b/docs/i18n/it/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ja/CHANGELOG.md b/docs/i18n/ja/CHANGELOG.md index 2d7e0cfad4c8..24c98673d06e 100644 --- a/docs/i18n/ja/CHANGELOG.md +++ b/docs/i18n/ja/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ko/CHANGELOG.md b/docs/i18n/ko/CHANGELOG.md index 4f1d131f4068..74fd9ad79e1b 100644 --- a/docs/i18n/ko/CHANGELOG.md +++ b/docs/i18n/ko/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/mr/CHANGELOG.md b/docs/i18n/mr/CHANGELOG.md index 135a0897f5ce..e266f5d9b718 100644 --- a/docs/i18n/mr/CHANGELOG.md +++ b/docs/i18n/mr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ms/CHANGELOG.md b/docs/i18n/ms/CHANGELOG.md index 7be5464855eb..d524d29e6437 100644 --- a/docs/i18n/ms/CHANGELOG.md +++ b/docs/i18n/ms/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/nl/CHANGELOG.md b/docs/i18n/nl/CHANGELOG.md index 7146457d8d63..7774f4a10cd2 100644 --- a/docs/i18n/nl/CHANGELOG.md +++ b/docs/i18n/nl/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/no/CHANGELOG.md b/docs/i18n/no/CHANGELOG.md index 5015dd14a597..26c171c916a6 100644 --- a/docs/i18n/no/CHANGELOG.md +++ b/docs/i18n/no/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/phi/CHANGELOG.md b/docs/i18n/phi/CHANGELOG.md index eebbf495a227..9a20d64c7533 100644 --- a/docs/i18n/phi/CHANGELOG.md +++ b/docs/i18n/phi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/pl/CHANGELOG.md b/docs/i18n/pl/CHANGELOG.md index c5438c7c1f36..32602f2adc69 100644 --- a/docs/i18n/pl/CHANGELOG.md +++ b/docs/i18n/pl/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/pt-BR/CHANGELOG.md b/docs/i18n/pt-BR/CHANGELOG.md index 1ed20ba1ee6f..ca9cc41b6c47 100644 --- a/docs/i18n/pt-BR/CHANGELOG.md +++ b/docs/i18n/pt-BR/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/pt/CHANGELOG.md b/docs/i18n/pt/CHANGELOG.md index 98f47c33deb8..affae234f10b 100644 --- a/docs/i18n/pt/CHANGELOG.md +++ b/docs/i18n/pt/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ro/CHANGELOG.md b/docs/i18n/ro/CHANGELOG.md index 5da09fd0efe7..0c2817f6ed4e 100644 --- a/docs/i18n/ro/CHANGELOG.md +++ b/docs/i18n/ro/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ru/CHANGELOG.md b/docs/i18n/ru/CHANGELOG.md index b192d8acf4a8..13f0518d1967 100644 --- a/docs/i18n/ru/CHANGELOG.md +++ b/docs/i18n/ru/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/sk/CHANGELOG.md b/docs/i18n/sk/CHANGELOG.md index 6d532a1c9f4c..00d5c97655a0 100644 --- a/docs/i18n/sk/CHANGELOG.md +++ b/docs/i18n/sk/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/sv/CHANGELOG.md b/docs/i18n/sv/CHANGELOG.md index dfab2b4dc381..19047c334469 100644 --- a/docs/i18n/sv/CHANGELOG.md +++ b/docs/i18n/sv/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/sw/CHANGELOG.md b/docs/i18n/sw/CHANGELOG.md index 02e5ed22aaeb..33b6c36e4807 100644 --- a/docs/i18n/sw/CHANGELOG.md +++ b/docs/i18n/sw/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ta/CHANGELOG.md b/docs/i18n/ta/CHANGELOG.md index 4240a81ffed8..475c7c6cd8da 100644 --- a/docs/i18n/ta/CHANGELOG.md +++ b/docs/i18n/ta/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/te/CHANGELOG.md b/docs/i18n/te/CHANGELOG.md index f56c824724fa..a931974f34ac 100644 --- a/docs/i18n/te/CHANGELOG.md +++ b/docs/i18n/te/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/th/CHANGELOG.md b/docs/i18n/th/CHANGELOG.md index 088f0176797b..8995374f7a75 100644 --- a/docs/i18n/th/CHANGELOG.md +++ b/docs/i18n/th/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/tr/CHANGELOG.md b/docs/i18n/tr/CHANGELOG.md index 8735a1e12591..3fd5ce84b6bd 100644 --- a/docs/i18n/tr/CHANGELOG.md +++ b/docs/i18n/tr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/uk-UA/CHANGELOG.md b/docs/i18n/uk-UA/CHANGELOG.md index e62124bcf848..9b9639ddd88a 100644 --- a/docs/i18n/uk-UA/CHANGELOG.md +++ b/docs/i18n/uk-UA/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/ur/CHANGELOG.md b/docs/i18n/ur/CHANGELOG.md index ead2495b688b..f6f58505405b 100644 --- a/docs/i18n/ur/CHANGELOG.md +++ b/docs/i18n/ur/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/vi/CHANGELOG.md b/docs/i18n/vi/CHANGELOG.md index 258ae8d459f1..bf6ba111d044 100644 --- a/docs/i18n/vi/CHANGELOG.md +++ b/docs/i18n/vi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/docs/i18n/zh-CN/CHANGELOG.md b/docs/i18n/zh-CN/CHANGELOG.md index 905a2c9ee01f..1ed5bb75fa4e 100644 --- a/docs/i18n/zh-CN/CHANGELOG.md +++ b/docs/i18n/zh-CN/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.31] — 2026-06-20 + ## [3.8.32] — TBD _See English CHANGELOG for v3.8.32 details._ diff --git a/tests/unit/cli-contexts.test.ts b/tests/unit/cli-contexts.test.ts index a5aaef335abd..c596e394c1bb 100644 --- a/tests/unit/cli-contexts.test.ts +++ b/tests/unit/cli-contexts.test.ts @@ -74,3 +74,21 @@ test("contexts.mjs (commands) pode ser importado sem erro", async () => { const mod = await import("../../bin/cli/commands/contexts.mjs"); assert.equal(typeof mod.registerContexts, "function"); }); + +test("confirm() declines cleanly on non-interactive stdin (no hung await)", async () => { + // Regression: `contexts remove` without --yes used to prompt even when stdin + // could not answer (pipe/CI/EOF), leaving the readline question pending and + // triggering Node's "unsettled top-level await" warning. With a non-TTY stdin + // confirm() must resolve to false immediately (decline) without touching + // readline — `--yes` remains the way to proceed non-interactively. + const { confirm } = await import("../../bin/cli/commands/contexts.mjs"); + const desc = Object.getOwnPropertyDescriptor(process.stdin, "isTTY"); + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + try { + const result = await confirm("Remove context 'x'?"); + assert.equal(result, false); + } finally { + if (desc) Object.defineProperty(process.stdin, "isTTY", desc); + else delete (process.stdin as { isTTY?: boolean }).isTTY; + } +});