Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
41619da
chore(release): open v3.8.42 cycle
diegosouzapw Jun 29, 2026
27a33be
chore: remove unused qdrant schema aliases (#5404)
JxnLexn Jun 29, 2026
4149dcf
chore: remove unused memory schema aliases (#5403)
JxnLexn Jun 29, 2026
898e8d0
chore: remove unused quota schema types (#5402)
JxnLexn Jun 29, 2026
537b565
chore: remove unused playground row type (#5401)
JxnLexn Jun 29, 2026
7bd0bc8
chore: remove unused codegraph exports (#5400)
JxnLexn Jun 29, 2026
be97882
chore: remove unused notion client type (#5399)
JxnLexn Jun 29, 2026
a4c0a95
chore: remove unused settings types (#5398)
JxnLexn Jun 29, 2026
34510fb
chore: remove unused combo types (#5396)
JxnLexn Jun 29, 2026
44757af
chore: remove unused provider types (#5393)
JxnLexn Jun 29, 2026
d650117
chore: remove unused skillssh skill type (#5392)
JxnLexn Jun 29, 2026
53ebc39
chore: remove unused status hex key type (#5391)
JxnLexn Jun 29, 2026
589c0a5
chore: remove unused batch provider type (#5390)
JxnLexn Jun 29, 2026
2c8f9c5
chore: remove unused skills schema types (#5389)
JxnLexn Jun 29, 2026
b52bb6d
chore: remove unused codex auth input type (#5388)
JxnLexn Jun 29, 2026
272fccc
chore: remove unused memory schema types (#5387)
JxnLexn Jun 29, 2026
30cee54
chore: remove unused playground row type (#5386)
JxnLexn Jun 29, 2026
5f7aecd
chore: remove unused qdrant schema types (#5385)
JxnLexn Jun 29, 2026
52f2575
chore: remove unused kiro social schema (#5384)
JxnLexn Jun 29, 2026
1970e7b
chore: remove unused memory schema types (#5383)
JxnLexn Jun 29, 2026
5c66eb9
chore: remove unused audit action type (#5382)
JxnLexn Jun 29, 2026
8e8d08e
chore: remove unused agent skills schema types (#5381)
JxnLexn Jun 29, 2026
f2d7aa9
chore: remove unused shared logger default export (#5380)
JxnLexn Jun 29, 2026
eaff010
chore: remove unused sse logger helpers (#5378)
JxnLexn Jun 29, 2026
f91eb28
chore: remove unused sse model legacy helpers (#5377)
JxnLexn Jun 29, 2026
4b82560
chore: remove unused v1 search response schema (#5376)
JxnLexn Jun 29, 2026
3578711
chore: remove unused cloud agent result schemas (#5375)
JxnLexn Jun 29, 2026
655fcca
chore: remove unused a2a routing logger readers (#5374)
JxnLexn Jun 29, 2026
3c28b93
chore: remove unused webhook delivery detail export (#5372)
JxnLexn Jun 29, 2026
79c39e7
chore: remove unused api key type (#5395)
JxnLexn Jun 29, 2026
a7a6263
chore: remove unused usage types (#5397)
JxnLexn Jun 29, 2026
d084b9c
chore: remove unused cloud agent input types (#5373)
JxnLexn Jun 29, 2026
0c42769
deps: bump electron from 42.4.1 to 42.5.1 in /electron (#5413)
dependabot[bot] Jun 29, 2026
50c9837
deps: bump the production group with 11 updates (#5414)
dependabot[bot] Jun 29, 2026
e9c7391
fix: frame non-streaming JSON responses (#5416)
rdself Jun 29, 2026
29bdb8d
fix(services): runNpm shell on win32 + prefix via env for Node 24 EIN…
diegosouzapw Jun 29, 2026
8d04875
fix(cli): restore dist/tls-options.mjs to npm tarball (#5452) (#5503)
diegosouzapw Jun 30, 2026
2a8309b
fix(dashboard): render onboarding wizard on /providers/new (#5427) (#…
diegosouzapw Jun 30, 2026
73f9580
fix(db): EBUSY-safe database import on Windows (#5406) (#5507)
diegosouzapw Jun 30, 2026
7491281
chore: remove unused gamification streak exports (#5463)
JxnLexn Jun 30, 2026
a003b1f
chore: remove unused headroom log tail export (#5464)
JxnLexn Jun 30, 2026
467736a
chore(dead-code): remove unused prompt cache control helper (#5466)
JxnLexn Jun 30, 2026
09fa990
chore(duplication): share vscode metadata helpers (#5471)
JxnLexn Jun 30, 2026
bbd9a77
chore(duplication): share auth zip extractors (#5475)
JxnLexn Jun 30, 2026
b3747c3
chore(duplication): share vscode tokenized request helper (#5479)
JxnLexn Jun 30, 2026
3150324
chore(duplication): share quota strategy ranking helpers (#5482)
JxnLexn Jun 30, 2026
e019ed4
chore(duplication): share recharts donut card (#5484)
JxnLexn Jun 30, 2026
e124b50
chore(duplication): share provider specific validation (#5485)
JxnLexn Jun 30, 2026
15eeaa3
chore(duplication): share batch response formatter (#5488)
JxnLexn Jun 30, 2026
3bc0d5f
chore(duplication): share redis runtime helpers (#5490)
JxnLexn Jun 30, 2026
1783f89
chore(duplication): share version manager request parsing (#5492)
JxnLexn Jun 30, 2026
21f8e44
chore(duplication): share media generation route helpers (#5493)
JxnLexn Jun 30, 2026
b9fd69e
chore(duplication): share settings transform schemas (#5496)
JxnLexn Jun 30, 2026
92c5115
chore(duplication): share relay stream finalizer (#5497)
JxnLexn Jun 30, 2026
2f3f8c7
chore(duplication): share machine id fallback (#5498)
JxnLexn Jun 30, 2026
c548008
chore(duplication): share node sqlite adapter (#5500)
JxnLexn Jun 30, 2026
8811468
fix: treat terminal stream cancels as complete (#5491)
JxnLexn Jun 30, 2026
3e03213
fix post-merge ci regressions (#5467)
KooshaPari Jun 30, 2026
3f8995d
fix: gate claude adaptive thinking defaults (#5480)
KooshaPari Jun 30, 2026
6b9c7d1
fix(fallback): normalize provider error rule headers (#5473)
KooshaPari Jun 30, 2026
c8814ed
fix(rate-limit): normalize queue refresh settings (#5499)
KooshaPari Jun 30, 2026
e522df1
chore(ci): add npm fetch-retry + release-freeze protocol (Hard Rule #…
diegosouzapw Jun 30, 2026
ae93cfb
chore(duplication): share service install helpers (#5495)
JxnLexn Jun 30, 2026
152ffc2
chore(duplication): share proxy route handlers (#5472)
JxnLexn Jun 30, 2026
78aaecb
chore(duplication): share combo builder model options (#5477)
JxnLexn Jun 30, 2026
36e771c
chore(dead-code): ratchet dead code baseline (#5468)
JxnLexn Jun 30, 2026
8388992
fix(dashboard): provider-add UX — i18n labels, surface import warning…
diegosouzapw Jun 30, 2026
8f5eda9
fix(providers): align Muse Spark (Meta AI) cookie copy to ecto_1_sess…
diegosouzapw Jun 30, 2026
f4b1aee
fix(providers): correct FriendliAI (serverless) + Novita (/openai/v1)…
diegosouzapw Jun 30, 2026
17b3669
fix(providers): gate import for tool-only providers + sanitize Coze v…
diegosouzapw Jun 30, 2026
2c07f23
fix(providers): correct LongCat free tier — GA LongCat-2.0, one-time …
backryun Jun 30, 2026
b09875d
fix(providers): Bytez OpenAI-compat base URL + auth-only key validati…
diegosouzapw Jun 30, 2026
2ce25e7
fix(providers): remove dead Phind provider + dedupe HuggingChat catal…
backryun Jun 30, 2026
285b13e
fix: protect dynamic dashboard tests with CSRF (#5405)
rdself Jun 30, 2026
7a06050
docs: clarify bifrost relay backend envs (#5520)
KooshaPari Jun 30, 2026
2c9a80b
test(quota): guard Claude-Code identity version lockstep (Phase 2) (#…
diegosouzapw Jun 30, 2026
47de0a1
feat(compression): T02 — honest default-on pipeline inflation guard (…
diegosouzapw Jun 30, 2026
1c882ed
feat(compression): T05/C2 — caveman dedup + ultra packs for de, fr, j…
diegosouzapw Jun 30, 2026
8946860
feat(compression): T05/C6 — Chinese (zh / wenyan) caveman pack + dete…
diegosouzapw Jun 30, 2026
a32cfb1
feat(compression): T07/R9 — gradle + dotnet RTK catalog filters (#5537)
diegosouzapw Jun 30, 2026
eea8182
refactor(dashboard): T11 — drop duplicate caveman on/off toggle from …
diegosouzapw Jun 30, 2026
76a3e1a
test relay routing fallback headers (#5526)
KooshaPari Jun 30, 2026
eb392aa
fix(opencode-plugin): bump to 0.2.0 + auto-publish on release (#5363)
herjarsa Jun 30, 2026
846b6be
add bifrost auto fallback cooldown
KooshaPari Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 7 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -1784,7 +1784,7 @@ QUOTA_STORE_DRIVER=sqlite # sqlite | redis
# Per-request timeout when proxying to the Bifrost gateway. Default: 30000 (30s).
# BIFROST_TIMEOUT_MS=
# Alias for BIFROST_API_KEY (used by scripts that read the env via
# OMNIROUTE_*). Falls back to BIFROST_API_KEY when unset.
# OMNIROUTE_*). BIFROST_API_KEY takes precedence when both are set.
# OMNIROUTE_BIFROST_KEY=
# Relay backend selection for the OpenAI-compatible relay endpoint:
# ts | bifrost | auto. "ts" (default when Bifrost is not configured) uses the
Expand All @@ -1796,6 +1796,10 @@ QUOTA_STORE_DRIVER=sqlite # sqlite | redis
# and X-Routing-Fallback.
# OMNIROUTE_RELAY_BACKEND=
# RELAY_ROUTING_BACKEND=
# Cooldown (ms) after a Bifrost sidecar hop fails in "auto" mode before the relay
# re-attempts the sidecar; it goes straight to the TS path while the cooldown lasts.
# 0 disables. Default 5000. Only applies when OMNIROUTE_RELAY_BACKEND=auto.
# OMNIROUTE_BIFROST_FAILURE_COOLDOWN_MS=
# Opt-in native HTTPS/TLS for `omniroute serve` (equivalent to --tls-cert /
# --tls-key). Provide BOTH a PEM certificate and its private key and the
# standalone server terminates TLS on the same listener (wss:// works
Expand Down Expand Up @@ -1850,6 +1854,8 @@ QUOTA_STORE_DRIVER=sqlite # sqlite | redis
# gateway as a separate sidecar (helps in 3+ replica deployments where you want
# provider rotation centralised). See docs/architecture/cluster-decisions.md §
# "Bifrost (bifrost profile)".
# Set OMNIROUTE_RELAY_BACKEND=auto to use this sidecar when healthy, or
# OMNIROUTE_RELAY_BACKEND=bifrost to require it without TS fallback.
# BIFROST_BASE_URL=http://bifrost:8080
# BIFROST_API_KEY=
# BIFROST_STREAMING_ENABLED=true
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,56 @@ jobs:
uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: 0
# Full history needed for auto-bump: git diff against previous release tag

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NPM_PUBLISH_NODE_VERSION }}
registry-url: https://registry.npmjs.org

- name: Auto-bump plugin version if plugin changed since last release
id: bump
working-directory: "@omniroute/opencode-plugin"
env:
CURRENT_TAG: ${{ github.ref_name }}
run: |
set -euo pipefail

PKG_VERSION=$(node -p "require('./package.json').version")
PKG_NAME=$(node -p "require('./package.json').name")

# 1) Skip if current version is not yet published (no bump needed)
PUBLISHED="$(npm view "${PKG_NAME}@${PKG_VERSION}" version 2>/dev/null || true)"
if [ "$PUBLISHED" != "$PKG_VERSION" ]; then
echo "✅ ${PKG_NAME}@${PKG_VERSION} is new — no bump needed."
echo "bumped=false" >> "$GITHUB_OUTPUT"
exit 0
fi

# 2) Find the previous release tag (exclude the current one)
PREV_TAG=$(git tag -l 'v*' --sort=-version:refname \
| grep -v "^${CURRENT_TAG}$" | head -1 || echo "")
if [ -z "$PREV_TAG" ]; then
echo "No previous tag to compare — skipping bump."
echo "bumped=false" >> "$GITHUB_OUTPUT"
exit 0
fi

# 3) Check if plugin dir actually changed since that tag
if git diff --quiet "$PREV_TAG" -- "@omniroute/opencode-plugin/"; then
echo "⏭️ No plugin changes since $PREV_TAG — nothing to publish."
echo "bumped=false" >> "$GITHUB_OUTPUT"
exit 0
fi

# 4) Auto-bump patch version
npm version patch --no-git-tag-version --allow-same-version
NEW_VERSION=$(node -p "require('./package.json').version")
echo "bumped=true" >> "$GITHUB_OUTPUT"
echo "📦 Auto-bumped ${PKG_NAME} from ${PKG_VERSION} to ${NEW_VERSION}"

- name: Install plugin dependencies
working-directory: "@omniroute/opencode-plugin"
run: npm install --no-audit --no-fund
Expand Down
10 changes: 10 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
# Keeping peer auto-install disabled prevents npm from pulling @lobehub/ui/mermaid
# back into the tree and reopening npm audit findings for unused packages.
legacy-peer-deps=true

# Network resilience: enlarge npm's fetch retry budget so a transient registry
# socket reset (ECONNRESET) mid-download retries instead of failing the job.
# npm defaults to only 2 retries with short timeouts; `npm ci` in
# electron-release.yml hit ECONNRESET during v3.8.41 publish. Applies to every
# CI workflow (electron / docker / unit) and local installs.
fetch-retries=5
fetch-retry-factor=4
fetch-retry-mintimeout=20000
fetch-retry-maxtimeout=120000
2 changes: 1 addition & 1 deletion @omniroute/opencode-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@omniroute/opencode-plugin",
"version": "0.1.0",
"version": "0.2.0",
"description": "OpenCode plugin for the OmniRoute AI Gateway. Drives dynamic model discovery, /connect auth flow, and multi-instance OmniRoute providers via the official @opencode-ai/plugin contract.",
"type": "module",
"main": "./dist/index.js",
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
## Project

Unified AI proxy/router — route any LLM through one endpoint. Multi-provider support
with **237 provider entries** (OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks,
with **236 provider entries** (OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks,
Cohere, NVIDIA, Cerebras, Pollinations, Puter, Cloudflare AI, HuggingFace, DeepInfra,
SambaNova, Meta Llama API, Moonshot AI, AI21 Labs, Databricks, Snowflake, and many more)
with **MCP Server** (94 tools), **A2A v0.3 Protocol**, and **Electron desktop app**.

> **Live counts (v3.8.40)**: providers 237 · MCP tools 94 · MCP scopes 30 · A2A skills 6 ·
> **Live counts (v3.8.40)**: providers 236 · MCP tools 94 · MCP scopes 30 · A2A skills 6 ·
> open-sse services 298 · routing strategies 17 · auto-combo scoring factors 12 ·
> DB modules 94 · DB migrations 106 · base tables 17 · search providers 11 ·
> i18n locales 42. **Refresh with `npm run check:docs-all`.**
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@

---

## [3.8.42] — TBD

### 🔧 Bug Fixes

- **providers (bytez):** fix Bytez key validation ("Provider validation endpoint not supported") and the chat base URL, verified live with a real key. Bytez **is** OpenAI-compatible at `…/models/v2/openai/v1`, but the registry stored the bare `…/models/v2` base, so the validation chat-probe hit `…/models/v2/chat/completions` → `404` → the misleading "endpoint not supported". Two parts: (1) the registry `baseUrl` now carries the full OpenAI-compat chat path (`…/models/v2/openai/v1/chat/completions`); (2) key validation no longer uses a chat probe — a Bytez account only serves models explicitly added to its catalog, so even valid keys 404 on any model id. A dedicated `validateBytezProvider` instead probes the **auth-only** `GET …/models/v2/list/tasks` endpoint (`200` ⇒ valid, `401/403` ⇒ invalid), which is independent of catalog provisioning. Regression guard: `tests/unit/bytez-validation-5422.test.ts`. ([#5422](https://github.com/diegosouzapw/OmniRoute/issues/5422))
- **dashboard (provider add):** two provider-add UX fixes. (1) #5420 — the "Import Models" button now stays hidden for **tool-only providers** (web search / web fetch), not just `*-search` ids: `firecrawl` and `jina-reader` (declared `serviceKinds: ["webFetch"]`) previously showed an Import button that hit the `400 "does not support models listing"` route. A new capability check (`providerLacksModelListing` over the resolved serviceKinds) gates the section without ever hiding an LLM/media provider. (2) #5426 — Coze key validation no longer leaks the raw upstream envelope (`{code,msg,logId,from}`) into the UI; the Coze-shaped error becomes a friendly `Coze rejected the key: <msg> (code <n>)` message (scoped to `provider === "coze"` so no other provider is affected). Regression guards: `tests/unit/model-listing-capability-5420.test.ts`, `tests/unit/coze-validation-error-5426.test.ts`. ([#5420](https://github.com/diegosouzapw/OmniRoute/issues/5420), [#5426](https://github.com/diegosouzapw/OmniRoute/issues/5426))
- **providers (friendliai, novita):** fix two provider registry endpoints that rejected valid keys (verified live with real keys). **FriendliAI** pointed at `…/dedicated/v1/chat/completions`, which `403 Forbidden`s a serverless `flp_*` token — switched to `…/serverless/v1/chat/completions` (+ a serverless `modelsUrl`). **Novita** pointed at the legacy `…/v3/…` base with a typo’d model id `ai-ai/llama-3.1-8b-instruct` (both `404`) — switched to the OpenAI-compatible `…/openai/v1/…` base + the valid `meta-llama/llama-3.1-8b-instruct` id. Regression guard: `tests/unit/provider-endpoints-friendliai-novita.test.ts`. ([#5430](https://github.com/diegosouzapw/OmniRoute/issues/5430), [#5455](https://github.com/diegosouzapw/OmniRoute/issues/5455))
- **providers (muse-spark):** align the Muse Spark Web (Meta AI) cookie copy with the live cookie name. The default session cookie migrated from the retired `abra_sess` to `ecto_1_sess` (`META_AI_DEFAULT_COOKIE`), but the provider form hint and one 401 auth-failure message still told users to paste `abra_sess` — a cookie that no longer exists. Both strings now name `ecto_1_sess`. Regression guard: `tests/unit/muse-spark-cookie-copy-5449.test.ts`. ([#5449](https://github.com/diegosouzapw/OmniRoute/issues/5449))
- **dashboard (provider add):** fix three rough edges in the Add-API-Key / model-import flow reported across the provider-catalog audit. (1) The **Validation Model** and **Account ID** form fields shipped untranslated i18n stub copy (`"Validation Model Id Label"`, `"Account Id Placeholder"`, …) that surfaced verbatim in the modal — replaced with real labels/placeholders/hints in `en.json`. (2) Model import **silently fell back to the cached/local catalog**: the route already returned a `warning` ("API unavailable — using local catalog"), but `useModelImportHandlers` only read `models`/`error` and dropped it, so the user got local models with no indication — the warning is now surfaced as an import log line (new pure helper `extractImportWarning`). (3) The required connection-**name** field defaulted to `""`, which let browser autofill inject garbage (e.g. `wiw`) — it now defaults to `"main"`. Regression guard: `tests/unit/provider-add-ux-i18n-import-warning.test.ts`. ([#5421](https://github.com/diegosouzapw/OmniRoute/issues/5421), [#5428](https://github.com/diegosouzapw/OmniRoute/issues/5428), [#5429](https://github.com/diegosouzapw/OmniRoute/issues/5429), [#5431](https://github.com/diegosouzapw/OmniRoute/issues/5431), [#5435](https://github.com/diegosouzapw/OmniRoute/issues/5435))
- **services (installer):** fix `spawn EINVAL` when installing an embedded service (9Router / CLIProxy) on **Windows + Node.js 24+**. Node 24 stopped letting `child_process.execFile()` run `.cmd` batch files without a shell (nodejs/node#52554), and npm on Windows is `npm.cmd`, so `runNpm()` threw `EINVAL` the moment a user clicked **Install**. `runNpm` now enables `shell` on win32 only. To keep Hard Rule #13 intact under a shell — where the shell, not `execFile`, parses argv — the install `--prefix` (a `DATA_DIR` path that can legitimately contain spaces, e.g. `C:\Users\John Doe\.omniroute\…`) is now passed via the `npm_config_prefix` **environment variable** instead of an argv path, and the user-supplied install `version` is constrained to a dist-tag/semver shape (`SERVICE_VERSION_PATTERN`) at the route boundary so it can never carry shell metacharacters. With the prefix in the environment and the version validated, every remaining argv entry is a static flag. Regression guards: `tests/unit/services/installers/runNpm-shell-5379.test.ts` (+ existing `ninerouter.test.ts` aligned to npm's `npm_config_prefix` env). ([#5379](https://github.com/diegosouzapw/OmniRoute/issues/5379))
- **cli (serve):** restore `dist/tls-options.mjs` to the npm tarball — the opt-in native HTTPS/TLS sidecar (#5361) was copied into the staged `dist/` by the build but then **pruned** by the prepublish allowlist step, so `omniroute serve` crashed on the published 3.8.41 with `ERR_MODULE_NOT_FOUND` (`dist/server-ws.mjs` imports `./tls-options.mjs`). Added `tls-options.mjs` to `APP_STAGING_ALLOWED_EXACT_PATHS` (survives the prune) and `dist/tls-options.mjs` to `PACK_ARTIFACT_REQUIRED_PATHS` (the `check:pack-artifact` gate now fails loudly if it ever vanishes again — same guard pattern as `webdav-handler.mjs`). Regression guards in `tests/unit/pack-artifact-policy.test.ts`. ([#5452](https://github.com/diegosouzapw/OmniRoute/issues/5452))
- **dashboard:** fix the **Add Provider / onboarding wizard** button silently doing nothing. The `/dashboard/providers/new` route was a redirect stub (it bounced straight back to `/dashboard/providers`), so every "Add Provider" button and dashboard widget link opened nothing, and the fully-built `ProviderOnboardingWizard` component stayed orphaned (never rendered by any route). The route now renders the wizard directly; auth is enforced centrally by the `(dashboard)` layout, same as the sibling provider routes. Regression guard in `tests/unit/onboarding-wizard-route-5427.test.ts`. ([#5427](https://github.com/diegosouzapw/OmniRoute/issues/5427))
- **db (import):** fix `EBUSY: resource busy or locked` when importing a database on **Windows**. The import route deleted the live `storage.sqlite` + WAL/`-shm`/`-journal` sidecars with a plain `fs.unlinkSync` immediately after `resetDbInstance()`, but Windows releases the SQLite file handle asynchronously after `close()` (mmap / antivirus), so the unlink raced and threw `EBUSY`. The route now deletes via `unlinkFileWithRetry` (EBUSY/EPERM backoff) — the same helper the restore path already uses. Regression guard in `tests/unit/db-import-ebusy-5406.test.ts`. ([#5406](https://github.com/diegosouzapw/OmniRoute/issues/5406), consolidated under [#5161](https://github.com/diegosouzapw/OmniRoute/issues/5161))
- **compression (pipeline):** add an honest default-on **inflation guard** to the stacked compression pipeline (T02 / Headroom H1). If the fully-stacked engines produce a body that did not actually shrink — its token count is `>=` the original — the compressed body is discarded and the verbatim original request is sent upstream instead, with a `pipeline-inflation-guard` warning recorded in the compression stats. This is safe by construction (the only fallback is the unmodified original, always a valid payload) and complements the existing opt-in per-step TV1 bail-out, which governs step-to-step advancement rather than the final output. New `open-sse/services/compression/pipelineGuards.ts`; wired at the single `finalizeStackedResult` choke point shared by the sync and async stacked paths. Regression guards (incl. an inflating-engine integration test) in `tests/unit/compression-pipeline-inflation-guard.test.ts`.

### ✨ New Features

- **compression (caveman):** complete the German, French, and Japanese rule packs with the `dedup` (repeated-context collapsing) and `ultra` (abbreviation / terse) categories they were missing — these three languages previously shipped only `context`/`filler`/`structural`, while `en`/`es`/`id`/`pt-BR` had all five. So a de/fr/ja conversation compressed at higher intensities now collapses repeated boilerplate ("wie bereits besprochen" → "Siehe oben.", "comme mentionné précédemment" → "Voir ci-dessus.", "前述のとおり" → "(上記参照)") and abbreviates dense technical vocabulary (`Datenbank`→`DB`, `Authentifizierung`→`Auth`; `base de données`→`BD`, `authentification`→`auth`; `データベース`→`DB`, `アプリケーション`→`app`). Patterns mirror the existing `es` pack and stay ReDoS-safe (bounded literal alternations; the CJK pack uses no `\b` since Japanese has no word boundaries). Regression guard: `tests/unit/caveman-packs-de-fr-ja.test.ts` (packs load + validate + shrink a representative sample). gaps v3.8.42 — T05/C2.

### ✨ New Features

- **compression (caveman):** add a **Chinese (zh / wenyan 文言) input-side rule pack** — the counterpart of the existing output-side `terse-cjk` style. New `rules/zh/{dedup,filler,ultra}.json` collapse repeated context ("如前所述" → "见上。"), drop pleasantries/hedging ("请帮我…/谢谢/我觉得"), strip sentence-final modal particles ("吗/呢/吧"), and abbreviate dense technical terms ("数据库"→"DB", "应用程序"→"app"). Chinese is now auto-detected: `detectCompressionLanguage` distinguishes zh from ja by Han-without-kana (kana is Japanese-exclusive, so a Han-heavy Japanese sentence still resolves to `ja`), and `zh` is listed in `listSupportedCompressionLanguages`. Patterns are ReDoS-safe (bounded literal alternations, no `\b` since CJK has no word boundaries). Regression guard: `tests/unit/caveman-packs-zh-wenyan.test.ts` (packs load + validate + shrink; zh/ja/non-CJK detection). gaps v3.8.42 — T05/C6.

### ✨ New Features

- **compression (RTK):** add **Gradle** and **.NET CLI (`dotnet`)** to the RTK tool-output filter catalog. Tool output for `gradle`/`gradlew` and `dotnet build|test|restore|publish` is now recognized (both by command and by output content) and compressed: Gradle daemon/welcome banners and no-op `> Task … UP-TO-DATE/SKIPPED/FROM-CACHE` lines are dropped while `BUILD SUCCESSFUL/FAILED`, "What went wrong", and stack traces are preserved; the .NET build banner, copyright, and `Determining projects to restore`/`Restored …` chatter are dropped while `Build succeeded/FAILED`, `error CS####`/`warning CS####`, and test summaries are preserved. New builtin filters `engines/rtk/filters/{gradle,dotnet}.json` (with inline tests run by the catalog gate) plus `gradle`/`dotnet` entries in the command detector. Regression guard: `tests/unit/rtk-gradle-dotnet-filters.test.ts`. gaps v3.8.42 — T07/R9.

---

## [3.8.41] — 2026-06-29

### ✨ New Features
Expand Down
Loading
Loading