mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-31 11:32:11 +03:00
Compare commits
125 Commits
fix/11787-
...
fix/v3850-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b574f0d14e | ||
|
|
cda832c3a7 | ||
|
|
1dd046814f | ||
|
|
26bfda3cb9 | ||
|
|
6f914b7a32 | ||
|
|
e93c5e765d | ||
|
|
d13c6cb19a | ||
|
|
9b9ea88d47 | ||
|
|
838fc00f25 | ||
|
|
a2c5d8a2f5 | ||
|
|
908c1b823d | ||
|
|
d812585b5a | ||
|
|
1b2c6f4c36 | ||
|
|
00bc397cda | ||
|
|
3d15294967 | ||
|
|
55f6b9808b | ||
|
|
039a425401 | ||
|
|
14dc6e8513 | ||
|
|
2da9ade59b | ||
|
|
6096ea51f8 | ||
|
|
54a1114382 | ||
|
|
82f09f4c86 | ||
|
|
09428da3d9 | ||
|
|
6a41a78132 | ||
|
|
ff4ac6c4d5 | ||
|
|
51e4930d05 | ||
|
|
476b20bd69 | ||
|
|
fe8ef4fa90 | ||
|
|
5d07bf32fe | ||
|
|
4d20d37974 | ||
|
|
1f4dc830f3 | ||
|
|
77f6f73706 | ||
|
|
32702d313b | ||
|
|
485c2dcdb6 | ||
|
|
f5742c3a8b | ||
|
|
52521984de | ||
|
|
385e90f444 | ||
|
|
d213ef0304 | ||
|
|
0b19c5a09b | ||
|
|
9903a6d2eb | ||
|
|
4c8074ba7a | ||
|
|
56dddfce34 | ||
|
|
8f38dcd32b | ||
|
|
4c187de99b | ||
|
|
e0029eb5a6 | ||
|
|
dfc84ba030 | ||
|
|
b07eaafcc4 | ||
|
|
131e413cbd | ||
|
|
212fba734f | ||
|
|
25aa95f0d0 | ||
|
|
23144ad644 | ||
|
|
4254b1fce1 | ||
|
|
66e02ec737 | ||
|
|
823dae0e9d | ||
|
|
3852e0534f | ||
|
|
15b164866c | ||
|
|
2471a0d95e | ||
|
|
81bf1ef98a | ||
|
|
41c6135257 | ||
|
|
22011437f8 | ||
|
|
8bed101303 | ||
|
|
ff0743071e | ||
|
|
41f4f83772 | ||
|
|
79b2e92c4e | ||
|
|
e96e40c035 | ||
|
|
097226b617 | ||
|
|
70af41b9f6 | ||
|
|
8180b3213a | ||
|
|
a3c19dd27c | ||
|
|
e620c50f3c | ||
|
|
2e3cd599b6 | ||
|
|
5684589ce7 | ||
|
|
ccee48d34a | ||
|
|
1c37fff056 | ||
|
|
c2c97aff82 | ||
|
|
faebf6de5f | ||
|
|
55691e0416 | ||
|
|
a1d6ff5fbf | ||
|
|
49827c1db1 | ||
|
|
47ea113b99 | ||
|
|
d26fe03801 | ||
|
|
92574de164 | ||
|
|
da678bd3ff | ||
|
|
2ec24e7c0b | ||
|
|
50bc8ab8aa | ||
|
|
4e11887085 | ||
|
|
38a29661d3 | ||
|
|
2463781e00 | ||
|
|
aa861a80d2 | ||
|
|
38e2baa879 | ||
|
|
d3420d29f1 | ||
|
|
5698769aba | ||
|
|
55e33f3dc8 | ||
|
|
36b7920db1 | ||
|
|
5fcd39bd6f | ||
|
|
e8b2cd208d | ||
|
|
f30e5b2675 | ||
|
|
ef668967f6 | ||
|
|
60dc242178 | ||
|
|
3b00535d04 | ||
|
|
2b8d3a8291 | ||
|
|
34e2f84c04 | ||
|
|
065d998407 | ||
|
|
d32c76f85a | ||
|
|
c9b1c12cfd | ||
|
|
c8dc982eaa | ||
|
|
9ec4d39a74 | ||
|
|
a9aee94a00 | ||
|
|
47f7e5a306 | ||
|
|
38e2616464 | ||
|
|
c4bd8b8ec4 | ||
|
|
e6de61f0c2 | ||
|
|
02ba573730 | ||
|
|
bd04bb9cc6 | ||
|
|
322b218f06 | ||
|
|
71093eda77 | ||
|
|
fb9cbe9566 | ||
|
|
674cc5feb1 | ||
|
|
d2ad71cf56 | ||
|
|
c705147de2 | ||
|
|
d8879371ea | ||
|
|
91f9a01fda | ||
|
|
87b3bdf85e | ||
|
|
31d3702a37 | ||
|
|
cb623b3cef |
89
.env.example
89
.env.example
@@ -45,6 +45,16 @@ INITIAL_PASSWORD=CHANGEME
|
||||
# executor's on-disk thread-sticky session cache. Leave unset to rely on DATA_DIR.
|
||||
# OMNIROUTE_DATA_DIR=/var/lib/omniroute
|
||||
|
||||
# Directory the runtime plugin scanner reads, overriding the home-derived default (#11827).
|
||||
# Used by: src/lib/plugins/scanner.ts — getDefaultPluginDir(); it is also the root the
|
||||
# plugin manager installs into. Set it in Docker/K8s to point straight at the bind-mounted
|
||||
# plugin tree, instead of moving HOME (which changes every other HOME-relative behaviour)
|
||||
# just to relocate the scan path. Unset = <HOME>/.omniroute/plugins, and
|
||||
# /tmp/.omniroute/plugins when the process exports no home at all.
|
||||
# Distinct from the CLI-only variable in section 9 that points the omniroute-cmd-* command
|
||||
# loader (bin/cli/plugins.mjs) at a package tree — this one drives the server-side scanner.
|
||||
# OMNIROUTE_PLUGINS_DIR=/opt/omniroute/plugins
|
||||
|
||||
# Escape hatch for the test-context DATA_DIR guard (#10428). A test run that never
|
||||
# chose a DATA_DIR is redirected to a throwaway temp dir so it cannot open the
|
||||
# operator's real database. Set to 1 only for a deliberate run against the real
|
||||
@@ -71,6 +81,11 @@ INITIAL_PASSWORD=CHANGEME
|
||||
# Never set this for the running server. Used by: src/lib/buildPhase.ts, src/lib/db/core.ts
|
||||
# OMNIROUTE_BUILDING=1
|
||||
|
||||
# Skip the optional native-dependency prebuild check for exotic vendored trees.
|
||||
# This does not make a missing dependency buildable. Used by: scripts/check/check-native-deps.mjs
|
||||
# Default: 0 | Set to 1 only when native dependencies are supplied out of band.
|
||||
# OMNIROUTE_SKIP_NATIVE_DEP_CHECK=0
|
||||
|
||||
# Encryption key for SQLite database encryption at rest.
|
||||
# Used by: src/lib/db/encryption.ts — encrypts the entire SQLite database.
|
||||
# Generate: openssl rand -hex 32 | Leave empty to disable DB encryption.
|
||||
@@ -658,21 +673,11 @@ NEXT_PUBLIC_CLOUD_URL=
|
||||
# open-sse/services/usage.ts.
|
||||
#OMNIROUTE_CROF_USAGE_URL=https://crof.ai/usage_api/
|
||||
#OMNIROUTE_CODEWHISPERER_BASE_URL=https://codewhisperer.us-east-1.amazonaws.com
|
||||
#OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/quota
|
||||
# OpenCode Go has no public quota API — this has no default and stays
|
||||
# unset unless you explicitly opt in to a self-hosted/mirrored endpoint:
|
||||
#OMNIROUTE_OPENCODE_GO_QUOTA_URL=
|
||||
#OMNIROUTE_OPENCODE_GO_DASHBOARD_URL=https://opencode.ai/workspace
|
||||
# Official OpenCode Go usage endpoint, authenticated with the connection API key.
|
||||
# Override only for relays or test fixtures.
|
||||
#OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/usage
|
||||
#OMNIROUTE_OLLAMA_CLOUD_USAGE_URL=https://ollama.com/settings
|
||||
|
||||
# OpenCode Go dashboard quota scraping. Prefer configuring these per connection
|
||||
# in Dashboard → Providers → OpenCode Go. Env vars are useful for headless
|
||||
# deployments or shared server defaults. The cookie is sensitive.
|
||||
#OPENCODE_GO_WORKSPACE_ID=wrk_...
|
||||
#OMNIROUTE_OPENCODE_GO_WORKSPACE_ID=wrk_...
|
||||
#OPENCODE_GO_AUTH_COOKIE=auth=...
|
||||
#OMNIROUTE_OPENCODE_GO_AUTH_COOKIE=auth=...
|
||||
|
||||
# OpenCode Go/Zen VPS egress (#5997): on a datacenter VPS, Cloudflare in front of
|
||||
# opencode.ai/zen/go 403s chat requests that lack OpenCode CLI identity headers.
|
||||
# When your clients don't already send them, set this to synthesize the CLI headers
|
||||
@@ -810,6 +815,10 @@ NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true
|
||||
# Windsurf has no default binary — set this to enable binary detection for it.
|
||||
# CLI_WINDSURF_BIN=windsurf
|
||||
# CLI_AUGGIE_BIN=auggie
|
||||
# CLI_5DIVE_BIN=5dive
|
||||
# 5dive keeps root-owned auth profiles under a system state dir (its own STATE_DIR,
|
||||
# default /var/lib/5dive); override here when it lives elsewhere.
|
||||
# CLI_5DIVE_STATE_DIR=/var/lib/5dive
|
||||
# AUGGIE_BIN=auggie
|
||||
|
||||
# ── ZCode (Z.ai GLM coding-plan CLI) local provider ──
|
||||
@@ -969,6 +978,11 @@ PROVIDER_LIMITS_SYNC_SPACING_MS=1500
|
||||
# Used by: src/lib/jobs/budgetResetJob.ts. Floor: 10000.
|
||||
#OMNIROUTE_BUDGET_RESET_JOB_INTERVAL_MS=600000
|
||||
|
||||
# Cron expression for the call-log export job (destinations configured in the
|
||||
# dashboard under Integrations > Log export). Default: hourly, on the hour.
|
||||
# Used by: src/lib/jobs/logExportJob.ts. Timezone: UTC.
|
||||
#OMNIROUTE_LOG_EXPORT_CRON=0 * * * *
|
||||
|
||||
# Emergency budget-exhaustion fallback (set false or 0 to disable the reroute to
|
||||
# nvidia/openai/gpt-oss-120b when a request fails with a 402 budget error).
|
||||
# Used by: open-sse/services/emergencyFallback.ts. Default: enabled.
|
||||
@@ -1455,17 +1469,25 @@ CURSOR_USER_AGENT="Cursor/3.4"
|
||||
# FIRECRAWL_BASE_URL=https://api.firecrawl.dev
|
||||
# FIRECRAWL_TIMEOUT_MS=30000 # Per-request timeout (default: 30000 = 30s)
|
||||
|
||||
# ── Claude TLS sidecar (Chromium-fingerprinted client) ──
|
||||
# Used by: open-sse/services/claudeTlsClient.ts — wire-level timeout for
|
||||
# the bogdanfinn/tls-client koffi binding and the JS-side grace window
|
||||
# layered on top of it when the native library is wedged.
|
||||
# ── ChatGPT browser transport (Firefox-fingerprinted client) ──
|
||||
# Used by: open-sse/services/chatgptTlsClient.ts — native wreq-js request
|
||||
# timeout and the JS-side hard-deadline grace layered on top of it.
|
||||
# OMNIROUTE_CHATGPT_TLS_TIMEOUT_MS=60000
|
||||
# OMNIROUTE_CHATGPT_TLS_GRACE_MS=10000
|
||||
# Max wait for the FIRST streamed byte before switching from direct streaming
|
||||
# to a buffered response, in milliseconds. Default 30000 (30s). The request's
|
||||
# hard deadline continues to apply while the buffered body is read.
|
||||
# OMNIROUTE_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS=30000
|
||||
|
||||
# ── Claude browser transport (Chromium-fingerprinted client) ──
|
||||
# Used by: open-sse/services/claudeTlsClient.ts — native wreq-js request
|
||||
# timeout and the JS-side hard-deadline grace layered on top of it.
|
||||
# OMNIROUTE_CLAUDE_TLS_TIMEOUT_MS=60000
|
||||
# OMNIROUTE_CLAUDE_TLS_GRACE_MS=10000
|
||||
|
||||
# ── Perplexity TLS sidecar (Firefox-fingerprinted client) ──
|
||||
# Used by: open-sse/services/perplexityTlsClient.ts — wire-level timeout for
|
||||
# the bogdanfinn/tls-client koffi binding and the JS-side grace window
|
||||
# layered on top of it when the native library is wedged.
|
||||
# ── Perplexity browser transport (Firefox-fingerprinted client) ──
|
||||
# Used by: open-sse/services/perplexityTlsClient.ts — native wreq-js request
|
||||
# timeout and the JS-side hard-deadline grace layered on top of it.
|
||||
# OMNIROUTE_PPLX_TLS_TIMEOUT_MS=30000
|
||||
# OMNIROUTE_PPLX_TLS_GRACE_MS=10000
|
||||
|
||||
@@ -1477,18 +1499,16 @@ CURSOR_USER_AGENT="Cursor/3.4"
|
||||
# meta-commentary. Set to 1/true/yes/on to restore the old behavior.
|
||||
# OMNIROUTE_PPLX_SEARCH_HINT=0
|
||||
|
||||
# ── Grok web TLS sidecar (Chrome-fingerprinted client) ──
|
||||
# Used by: open-sse/services/grokTlsClient.ts — wire-level timeout for the
|
||||
# bogdanfinn/tls-client koffi binding and the JS-side grace window layered on
|
||||
# top of it when the native library is wedged.
|
||||
# ── Grok web browser transport (Chrome-fingerprinted client) ──
|
||||
# Used by: open-sse/services/grokTlsClient.ts — native wreq-js request timeout
|
||||
# and the JS-side hard-deadline grace layered on top of it.
|
||||
# OMNIROUTE_GROK_TLS_TIMEOUT_MS=60000
|
||||
# OMNIROUTE_GROK_TLS_GRACE_MS=10000
|
||||
|
||||
# ── Notion web TLS sidecar (Chrome-fingerprinted client) ──
|
||||
# Used by: open-sse/services/notionTlsClient.ts — wire-level timeout for the
|
||||
# bogdanfinn/tls-client koffi binding and the JS-side grace window layered on
|
||||
# top of it when the native library is wedged. The notion-web executor raises
|
||||
# the wire timeout per-request to 180000 for long generations.
|
||||
# ── Notion web browser transport (Chrome-fingerprinted client) ──
|
||||
# Used by: open-sse/services/notionTlsClient.ts — native wreq-js request timeout
|
||||
# and the JS-side hard-deadline grace layered on top of it. The notion-web
|
||||
# executor raises the native timeout per-request to 180000 for long generations.
|
||||
# OMNIROUTE_NOTION_TLS_TIMEOUT_MS=30000
|
||||
# OMNIROUTE_NOTION_TLS_GRACE_MS=10000
|
||||
|
||||
@@ -1749,6 +1769,7 @@ APP_LOG_TO_FILE=true
|
||||
|
||||
# Custom directory for CLI plugin discovery (omniroute-cmd-* packages).
|
||||
# Default: ~/.omniroute/plugins/ Override in dev/CI to point at a local plugin tree.
|
||||
# CLI-only: the server-side plugin scanner is pointed by OMNIROUTE_PLUGINS_DIR (section 2).
|
||||
# OMNIROUTE_PLUGIN_PATH=
|
||||
|
||||
# ── Prompt cache (system prompt deduplication) ──
|
||||
@@ -2017,6 +2038,8 @@ APP_LOG_TO_FILE=true
|
||||
# CLIPROXYAPI_HOST=127.0.0.1
|
||||
# CLIPROXYAPI_PORT=5544
|
||||
# CLIPROXYAPI_CONFIG_DIR=~/.cli-proxy-api
|
||||
# Data-plane key fallback; the cliproxyapi_api_key setting takes precedence.
|
||||
# CLIPROXYAPI_API_KEY=
|
||||
# Management key for an externally managed instance. Embedded instances use
|
||||
# OmniRoute's encrypted service key.
|
||||
# CLIPROXYAPI_MANAGEMENT_KEY=
|
||||
@@ -2120,6 +2143,12 @@ APP_LOG_TO_FILE=true
|
||||
# Used by: open-sse/services/rateLimitManager.ts
|
||||
# RATE_LIMIT_MAX_WAIT_MS=15000
|
||||
|
||||
# Limiter-managed execution backstop (Bottleneck `expiration`): bounds a job's
|
||||
# post-dispatch execution, never queue wait. Must stay ABOVE upstream
|
||||
# fetch-start timeouts on non-incremental gateways. Default: 600000 (10 min)
|
||||
# Used by: open-sse/services/rateLimitManager.ts
|
||||
# RATE_LIMIT_EXECUTION_MAX_WAIT_MS=600000
|
||||
|
||||
# Rate limit queue admission cap: reject with 429 queue_full once this many requests
|
||||
# are already queued (0 = disabled/unbounded, the default). Used by: open-sse/services/rateLimitManager.ts
|
||||
# RATE_LIMIT_MAX_QUEUE_DEPTH=0
|
||||
|
||||
36
.github/workflows/api-route-typecheck.yml
vendored
Normal file
36
.github/workflows/api-route-typecheck.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: API Route Typecheck
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- "release/**"
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
api-typecheck:
|
||||
name: API Route Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: npm
|
||||
- uses: ./.github/actions/npm-ci-retry
|
||||
- name: Reject new API-route TypeScript diagnostics
|
||||
run: node scripts/check/check-api-typecheck.mjs
|
||||
- name: API typecheck gate unit tests
|
||||
run: node --import tsx/esm --test tests/unit/build/check-api-typecheck.test.ts
|
||||
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -109,8 +109,11 @@ jobs:
|
||||
.eslintcache
|
||||
.eslintcache-complexity
|
||||
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
|
||||
restore-keys: |
|
||||
eslint-${{ runner.os }}-
|
||||
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
|
||||
# cache built under a different suppressions file / lint config / lockfile reports
|
||||
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
|
||||
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
|
||||
# partial cache from another configuration.
|
||||
# Single ESLint inventory (JSON) — quality-gate reuses the artifact instead of
|
||||
# a second cold full-tree pass for eslintWarnings ratchet counts.
|
||||
- name: ESLint (JSON report)
|
||||
@@ -209,8 +212,11 @@ jobs:
|
||||
.eslintcache
|
||||
.eslintcache-complexity
|
||||
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
|
||||
restore-keys: |
|
||||
eslint-${{ runner.os }}-
|
||||
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
|
||||
# cache built under a different suppressions file / lint config / lockfile reports
|
||||
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
|
||||
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
|
||||
# partial cache from another configuration.
|
||||
# Coverage mergeada (coverage-summary.json) p/ o ratchet de cobertura.
|
||||
# continue-on-error: o artifact pode não existir se a job test-coverage foi
|
||||
# SKIPPED (shard flaky). Nesse caso collect-metrics pula coverage.* (ausente sem
|
||||
@@ -621,9 +627,9 @@ jobs:
|
||||
# 13:50Z the kernel OOM-killed main's build while a PR build ran beside it
|
||||
# (five Build jobs had been queued by a burst of PRs). Two lanes: main keeps
|
||||
# its own so a release is never queued behind PR traffic; PR builds serialize
|
||||
# among themselves. GitHub keeps one running + one pending per group and
|
||||
# CANCELS older pendings — a cancelled PR build is re-runnable; a dead main
|
||||
# build costs the publish its artefact and a 40-minute rebuild that OOMs.
|
||||
# among themselves. docker-publish.yml's amd64 leg joins `heavy-build-main`
|
||||
# so a :next image build waits beside this artefact instead of becoming the
|
||||
# third heavy (#11976). GitHub keeps one running + one pending per group.
|
||||
concurrency:
|
||||
group: heavy-build-${{ github.ref == 'refs/heads/main' && 'main' || 'pr' }}
|
||||
cancel-in-progress: false
|
||||
|
||||
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -22,10 +22,10 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
- uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
|
||||
with:
|
||||
languages: javascript-typescript
|
||||
queries: security-extended
|
||||
- uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
- uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
|
||||
with:
|
||||
category: "/language:javascript-typescript"
|
||||
|
||||
44
.github/workflows/docker-publish.yml
vendored
44
.github/workflows/docker-publish.yml
vendored
@@ -26,6 +26,14 @@ on:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# One publish per ref. A merge storm used to fan out 8 concurrent hosted builds,
|
||||
# every one OOM-killing `npm run build` inside BuildKit (#11976). The :next
|
||||
# channel only needs the newest SHA; cancel-in-progress is the same pattern as
|
||||
# quality.yml / nightly-release-green.
|
||||
concurrency:
|
||||
group: docker-publish-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Least-privilege default: read-only at the top level; the build and merge jobs that
|
||||
# push to GHCR grant packages: write themselves (Scorecard TokenPermissions).
|
||||
permissions:
|
||||
@@ -118,7 +126,23 @@ jobs:
|
||||
name: Build Docker (${{ matrix.platform }})
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.skip != 'true'
|
||||
runs-on: ${{ matrix.runner }}
|
||||
# amd64: the .113 omni-build pool (31 GB / 32 cores, ONE listener since
|
||||
# #12048). Hosted ubuntu-24.04 is ~7 GB and dies ResourceExhausted (#11976).
|
||||
# Falls back to hosted when USE_VPS_RUNNER is off. arm64: no ARM box — stay
|
||||
# on GitHub's ubuntu-24.04-arm.
|
||||
# Webpack on BOTH arches: Turbopack on omniroute-113-6 hit
|
||||
# TurbopackInternalError "there must be a path to a root" after 26 min
|
||||
# (run 33253576569). The same tree's arm64 webpack build on hosted ARM
|
||||
# succeeded (run 33264823398). Dockerfile already documents webpack as the
|
||||
# Docker escape hatch (OMNIROUTE_USE_TURBOPACK=0).
|
||||
runs-on: ${{ matrix.arch == 'amd64' && (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-build"]') || 'ubuntu-24.04') || 'ubuntu-24.04-arm' }}
|
||||
# Share the 1-slot omni-build ceiling (#12048) with ci.yml `Build` /
|
||||
# npm-publish. Same group as main's Build so a :next publish waits beside
|
||||
# the artefact instead of sitting next to it. arm64 is hosted — its own
|
||||
# group, cancelled by the workflow-level concurrency.
|
||||
concurrency:
|
||||
group: ${{ matrix.arch == 'amd64' && 'heavy-build-main' || format('docker-publish-arm-{0}', github.ref) }}
|
||||
cancel-in-progress: ${{ matrix.arch != 'amd64' }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -127,10 +151,8 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- platform: linux/amd64
|
||||
runner: ubuntu-24.04
|
||||
arch: amd64
|
||||
- platform: linux/arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
env:
|
||||
IMAGE_NAME: diegosouzapw/omniroute
|
||||
@@ -143,6 +165,9 @@ jobs:
|
||||
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/v{0}', inputs.version) || '' }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Assert Docker Engine
|
||||
run: docker info
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
@@ -166,6 +191,8 @@ jobs:
|
||||
context: .
|
||||
target: runner-base
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
OMNIROUTE_USE_TURBOPACK=0
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}
|
||||
@@ -183,6 +210,8 @@ jobs:
|
||||
context: .
|
||||
target: runner-web
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
OMNIROUTE_USE_TURBOPACK=0
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}
|
||||
@@ -208,6 +237,8 @@ jobs:
|
||||
file: Dockerfile.bun
|
||||
target: runner-base
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
OMNIROUTE_USE_TURBOPACK=0
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}
|
||||
@@ -233,6 +264,8 @@ jobs:
|
||||
file: Dockerfile.bun
|
||||
target: runner-web
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
OMNIROUTE_USE_TURBOPACK=0
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}
|
||||
@@ -495,11 +528,14 @@ jobs:
|
||||
severity: CRITICAL
|
||||
ignore-unfixed: true
|
||||
exit-code: "1"
|
||||
# Explicit: the advisory scan above already points at it, and the blocking
|
||||
# gate must honour the same accepted-risk list (#12084).
|
||||
trivyignores: .trivyignore
|
||||
|
||||
- name: Upload Trivy SARIF to Security tab
|
||||
if: needs.prepare.outputs.version != 'main'
|
||||
continue-on-error: true
|
||||
uses: github/codeql-action/upload-sarif@v4.37.7
|
||||
uses: github/codeql-action/upload-sarif@v4.37.8
|
||||
with:
|
||||
sarif_file: trivy-results.sarif
|
||||
category: trivy-image
|
||||
|
||||
15
.github/workflows/electron-release.yml
vendored
15
.github/workflows/electron-release.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
# A dispatch builds the ref it is dispatched ON (`gh workflow run … --ref v3.8.50` rebuilds
|
||||
# that tag; `--ref main` builds the repaired line). The ref is deliberately NOT an input:
|
||||
# CodeQL flags an input-controlled checkout next to the npm cache on the default branch as
|
||||
# cache poisoning (actions/cache-poisoning/poisonable-step), and `github.ref` is trusted.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
@@ -233,7 +237,7 @@ jobs:
|
||||
# optionals (@img/sharp-*, @img/sharp-libvips-*, @ngrok/ngrok-*,
|
||||
# fsevents) carry linux forks. Replace them with the forks this
|
||||
# leg's own `npm ci` resolved, then assert every bundled native
|
||||
# (koffi triplets, better-sqlite3 prebuilds, wreq-js, onnxruntime)
|
||||
# (better-sqlite3 prebuilds, wreq-js, onnxruntime)
|
||||
# can service this leg's platform/arch before packaging starts.
|
||||
run: |
|
||||
node scripts/build/standaloneBundle.mjs restore --archive web-bundle.tar.gz
|
||||
@@ -417,7 +421,14 @@ jobs:
|
||||
tag_name: ${{ needs.validate.outputs.version }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
generate_release_notes: true
|
||||
# NEVER. Phase 3 of the release flow creates the GitHub Release with the curated
|
||||
# notes seconds after pushing the tag, so by the time this step runs (1-2 h of
|
||||
# builds later) the body already exists — and `true` APPENDS GitHub's
|
||||
# auto-generated "What's Changed" block to it (v3.8.48 shipped that way; the
|
||||
# v3.8.50 re-attach dispatch added +1,416 chars to a 121 KB body, run
|
||||
# 33238093090). A curated body sits ~3 KB under the 125,000-char cap, so the
|
||||
# append can also turn this step RED and leave the release with no assets.
|
||||
generate_release_notes: false
|
||||
fail_on_unmatched_files: false
|
||||
files: |
|
||||
release-assets/*.dmg
|
||||
|
||||
115
.github/workflows/nightly-release-green.yml
vendored
115
.github/workflows/nightly-release-green.yml
vendored
@@ -196,6 +196,26 @@ jobs:
|
||||
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
|
||||
fi
|
||||
|
||||
- name: Close tracking issue when the branch is green again
|
||||
if: steps.validate.outputs.exit == '0'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TARGET: ${{ steps.branch.outputs.target }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# The open/update step above is the UPWARD half of the loop; without this
|
||||
# step a stale "not green" issue outlives the fix and every base-green check
|
||||
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
|
||||
TITLE="🔴 Release branch not green: ${TARGET}"
|
||||
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
|
||||
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
||||
if [ -n "$EXISTING" ]; then
|
||||
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
|
||||
--comment "✅ \`${TARGET}\` is release-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
|
||||
echo "Closed issue #$EXISTING"
|
||||
fi
|
||||
|
||||
- name: Upload report artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -294,6 +314,25 @@ jobs:
|
||||
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
|
||||
fi
|
||||
|
||||
- name: Close tracking issue when the branch is green again
|
||||
if: steps.validate.outputs.exit == '0'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# The open/update step above is the UPWARD half of the loop; without this
|
||||
# step a stale "not green" issue outlives the fix and every base-green check
|
||||
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
|
||||
TITLE="🔴 main branch not green"
|
||||
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
|
||||
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
||||
if [ -n "$EXISTING" ]; then
|
||||
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
|
||||
--comment "✅ \`main\` is main-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
|
||||
echo "Closed issue #$EXISTING"
|
||||
fi
|
||||
|
||||
- name: Upload report artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -384,6 +423,13 @@ jobs:
|
||||
# on `improvements`, complexity-ratchets only when `.improved`), and both exit
|
||||
# non-zero while the branch is over baseline — which is exactly when there is
|
||||
# nothing to bank. Their exit code is not the signal; the verifier below is.
|
||||
# Velocity phase (quality-baseline.json `_policy`, relax-baselines.mjs): the caps
|
||||
# were raised on purpose, so banking the measured shrink would silently undo the
|
||||
# 20% headroom every night. Pause the downward ratchet until the phase closes.
|
||||
if node -e 'process.exit(require("./config/quality/quality-baseline.json")._policy?.phase === "velocity" ? 0 : 1)'; then
|
||||
echo "Velocity phase active — ratchet banking paused (see docs/architecture/QUALITY_GATES.md → Velocity phase)."
|
||||
exit 0
|
||||
fi
|
||||
set +e
|
||||
node scripts/check/check-file-size.mjs --update
|
||||
node scripts/check/check-complexity-ratchets.mjs --update
|
||||
@@ -445,3 +491,72 @@ jobs:
|
||||
gh pr create --repo "$GITHUB_REPOSITORY" --base "$TARGET" --head "$BANK_BRANCH" \
|
||||
--title "chore(quality): bank ratchet shrinks (${TARGET})" --body-file pr-body.md
|
||||
fi
|
||||
|
||||
# ── Baseline headroom (velocity phase, 2026-08-30 → v4.0) ──────────────────────
|
||||
# The ratchets only speak when a baseline is crossed. With every baseline loosened by
|
||||
# 20% (scripts/quality/relax-baselines.mjs) the question is how fast the budget is
|
||||
# being consumed — this job measures each gate the way CI does and posts the headroom
|
||||
# table to one living issue, so a budget that fills in a week is visible before the
|
||||
# first red PR. Advisory: never fails the workflow.
|
||||
baseline-headroom:
|
||||
name: Baseline headroom
|
||||
if: ${{ github.event_name != 'push' }}
|
||||
timeout-minutes: 60
|
||||
runs-on: ${{ (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-light"]')) || 'ubuntu-latest' }}
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: npm
|
||||
|
||||
- uses: ./.github/actions/npm-ci-retry
|
||||
|
||||
- name: Measure headroom on ${{ github.ref_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node scripts/quality/baseline-headroom.mjs \
|
||||
--json reports/quality/headroom.json --md reports/quality/headroom.md
|
||||
cat reports/quality/headroom.md >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Upload headroom report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: baseline-headroom-${{ github.run_id }}
|
||||
path: reports/quality/headroom.*
|
||||
retention-days: 90
|
||||
|
||||
- name: Post to the living issue
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TITLE="📈 Baseline headroom (velocity phase)"
|
||||
BAD=$(node -e 'const r=require("./reports/quality/headroom.json").rows;console.log(r.filter(x=>x.status==="critical"||x.status==="warn").length)')
|
||||
{
|
||||
echo "Branch: \`${GITHUB_REF_NAME}\` · run: ${RUN_URL}"
|
||||
echo ""
|
||||
cat reports/quality/headroom.md
|
||||
} > headroom-comment.md
|
||||
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
|
||||
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
||||
if [ -z "$EXISTING" ]; then
|
||||
EXISTING=$(gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label quality-gate-finding \
|
||||
--body "Living tracker for the velocity-phase baseline budget (docs/architecture/QUALITY_GATES.md → Velocity phase). One comment per nightly run; the newest comment is the current state." \
|
||||
| grep -oE '[0-9]+$')
|
||||
fi
|
||||
gh issue comment "$EXISTING" --repo "$GITHUB_REPOSITORY" --body-file headroom-comment.md
|
||||
if [ "$BAD" != "0" ]; then
|
||||
gh issue edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --add-label "headroom-alert" 2>/dev/null || true
|
||||
else
|
||||
gh issue edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --remove-label "headroom-alert" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
15
.github/workflows/npm-publish.yml
vendored
15
.github/workflows/npm-publish.yml
vendored
@@ -273,11 +273,20 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Attach SBOM to GitHub Release
|
||||
if: steps.resolve.outputs.skip != 'true' && github.event_name == 'release'
|
||||
# Not only on the `release` event: the v3.8.50 package shipped through a
|
||||
# workflow_dispatch (staged publish, 11 attempts) and this step was skipped, so the
|
||||
# GitHub Release carried no SBOM until it was attached by hand from the run's
|
||||
# `sbom-npm` artifact. Attach whenever a release for the published tag exists.
|
||||
if: steps.resolve.outputs.skip != 'true' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: gh release upload "$TAG" sbom-npm.cdx.json --clobber
|
||||
TAG: ${{ github.event_name == 'release' && github.ref_name || format('v{0}', inputs.version) }}
|
||||
run: |
|
||||
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "::notice::no GitHub Release for $TAG yet — SBOM stays on the sbom-npm workflow artifact"
|
||||
exit 0
|
||||
fi
|
||||
gh release upload "$TAG" sbom-npm.cdx.json --repo "$GITHUB_REPOSITORY" --clobber
|
||||
|
||||
# WS1.2/WS1.3 (#7065 class): the artifact that is about to be published must
|
||||
# BOOT. build:cli already assembled dist/ above; this packs+installs+boots the
|
||||
|
||||
11
.github/workflows/quality.yml
vendored
11
.github/workflows/quality.yml
vendored
@@ -70,7 +70,16 @@ jobs:
|
||||
# 2026-08-14: 72 of the last 100 PRs into release/** came from forks, so the fork case is
|
||||
# the majority of the traffic, not the exception — this job earns its place, it just should
|
||||
# not duplicate build.yml for the own-origin 28%.
|
||||
if: ${{ github.event_name != 'pull_request' || ((github.event.pull_request.draft == false || startsWith(github.head_ref, 'mergify/merge-queue/')) && needs.changes.outputs.code == 'true' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||
# Disabled 2026-08-29 (#11976 follow-up). `continue-on-error: true` still
|
||||
# reports a GitHub check FAILURE, so every fork PR into release/** was born
|
||||
# with a red "Build (advisory)" even when every required gate was green
|
||||
# (sweep-reds, 41 PRs). Hosted ubuntu-latest cannot finish `npm run build`
|
||||
# on this tree — VM shutdown ~6 min in, same class as build.yml going
|
||||
# workflow_dispatch-only in #11962. Pre-merge build signal for release/**
|
||||
# is nightly-release-green (omni-build); for main it is ci.yml `Build`.
|
||||
# Restore this job when a runner that actually fits the tree is wired here.
|
||||
# Bare `false` (not `${{ false }}`) — zizmor obfuscation flags the expression form.
|
||||
if: false
|
||||
# PINNED to hosted — this was the last job in THIS workflow still on the USE_VPS_RUNNER
|
||||
# switch (ci.yml's Build, nightly-release-green and npm-publish keep it, so the variable
|
||||
# stays meaningful), and with USE_VPS_RUNNER=true it produced NO signal at all here.
|
||||
|
||||
5
.github/workflows/scorecard.yml
vendored
5
.github/workflows/scorecard.yml
vendored
@@ -4,12 +4,15 @@ on:
|
||||
schedule:
|
||||
- cron: "27 7 * * 1"
|
||||
push:
|
||||
branches: ["main"]
|
||||
# Scorecard only accepts the DEFAULT branch — here the active release/vX.Y.Z,
|
||||
# not `main`. The job below guards on it so a push to any other branch skips.
|
||||
branches: ["main", "release/**"]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
if: ${{ github.event_name != 'push' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
|
||||
10
.trivyignore
10
.trivyignore
@@ -19,4 +19,12 @@
|
||||
# Keep this list SHORT and reviewed every release. Prefer fixing (rebuild on a
|
||||
# patched base / bump the dep) over suppressing. Stale entries are debt.
|
||||
#
|
||||
# (No accepted-risk suppressions at present — ignore-unfixed covers the noise.)
|
||||
# CVE-2025-68121 — Go stdlib crypto/tls (session-resumption certificate validation)
|
||||
# inside the PREBUILT bogdanfinn/tls-client v1.15.1 .so that tls-client-node's
|
||||
# postinstall downloads (built with go 1.24.1; fixed in 1.24.13). No upstream
|
||||
# rebuild exists (v1.15.1 is still the latest release) and nothing in this repo
|
||||
# can bump it. The binary is only loaded by the browser-TLS web-provider
|
||||
# executors (claude-web / grok-web / lmarena / perplexity-web / notion-web),
|
||||
# whose handshakes go through utls. Tracking issue: #12084. Revisit at the next
|
||||
# tls-client release or base-image bump and BEFORE the v3.8.51 tag (2026-09-15).
|
||||
CVE-2025-68121
|
||||
|
||||
18
AGENTS.md
18
AGENTS.md
@@ -56,7 +56,7 @@ Repository map and Reference Documentation sections below.
|
||||
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
|
||||
| Transformer | `open-sse/transformer/` | Responses API ↔ Chat Completions |
|
||||
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
|
||||
| Database | `src/lib/db/` | SQLite domain modules (166 migrations) |
|
||||
| Database | `src/lib/db/` | SQLite domain modules (167 migrations) |
|
||||
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
|
||||
| MCP Server | `open-sse/mcp-server/` | 110 tools (44 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
|
||||
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
|
||||
@@ -289,8 +289,7 @@ When creating _any_ validation tests or one-off logic scripts, default to `scrip
|
||||
### Database
|
||||
|
||||
- **Always** go through `src/lib/db/` domain modules — **never** write raw SQL in routes or handlers
|
||||
- **Never** add logic to `src/lib/localDb.ts` (re-export layer only)
|
||||
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules instead
|
||||
- **Never** barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
|
||||
- DB singleton: `getDbInstance()` from `src/lib/db/core.ts` (WAL journaling)
|
||||
- Migrations: `src/lib/db/migrations/` — versioned SQL files, idempotent, run in transactions
|
||||
|
||||
@@ -355,8 +354,7 @@ Documentation must describe verified behavior, not plausible behavior.
|
||||
1. Create `src/lib/db/yourModule.ts` — import `getDbInstance` from `./core.ts`
|
||||
2. Export CRUD functions for your domain table(s)
|
||||
3. Add migration in `src/lib/db/migrations/` if new tables needed
|
||||
4. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
|
||||
5. Write tests
|
||||
4. Write tests
|
||||
|
||||
### Adding a New MCP Tool
|
||||
|
||||
@@ -399,6 +397,9 @@ Documentation must describe verified behavior, not plausible behavior.
|
||||
- Eval suite: `src/lib/evals/` → docs: `docs/frameworks/EVALS.md`
|
||||
- Skill (sandbox): `src/lib/skills/` → docs: `docs/frameworks/SKILLS.md`
|
||||
- Webhook event: `src/lib/webhookDispatcher.ts` → docs: `docs/frameworks/WEBHOOKS.md`
|
||||
- Log-export destination: add `src/lib/logExport/destinations/<name>.ts` + one line in
|
||||
`src/lib/logExport/registry.ts` → docs: `docs/frameworks/LOG-EXPORT.md`. The runner, REST layer
|
||||
and dashboard form all read the registry, so nothing else changes.
|
||||
|
||||
---
|
||||
|
||||
@@ -424,6 +425,7 @@ For any non-trivial change, read the matching deep-dive first:
|
||||
| Evals | `docs/frameworks/EVALS.md` |
|
||||
| Compliance / audit | `docs/security/COMPLIANCE.md` |
|
||||
| Webhooks | `docs/frameworks/WEBHOOKS.md` |
|
||||
| Log export (call logs → BigQuery/…) | `docs/frameworks/LOG-EXPORT.md` |
|
||||
| Authorization pipeline | `docs/architecture/AUTHZ_GUIDE.md` |
|
||||
| Stealth (TLS / fingerprint) | `docs/security/STEALTH_GUIDE.md` |
|
||||
| Agent protocols (A2A / ACP / Cloud) | `docs/frameworks/AGENT_PROTOCOLS_GUIDE.md` |
|
||||
@@ -657,6 +659,10 @@ procedures are in [`docs/architecture/QUALITY_GATES.md`](docs/architecture/QUALI
|
||||
`npm run quality:ratchet -- --update` when a metric genuinely improves.
|
||||
- Job `test-vitest` runs `npm run test:vitest` (MCP tools, autoCombo, cache) — blocking.
|
||||
`test:vitest:ui` has been blocking since PR #7127.
|
||||
- **Velocity phase (2026-08-30 → v4.0)**: every numeric baseline is loosened by 20% and
|
||||
`--require-tighten` is advisory (`quality-baseline.json` → `_policy`); the nightly
|
||||
`baseline-headroom` job tracks how much of the budget is left in the issue
|
||||
"📈 Baseline headroom". See `docs/architecture/QUALITY_GATES.md` → "Velocity phase".
|
||||
|
||||
**Allowlist policy (short form):** Fix the cause; use the allowlist only for pre-existing
|
||||
violations you cannot fix in the same PR. Add a comment with justification + issue number.
|
||||
@@ -668,7 +674,7 @@ the stale-enforcement added in Fase 6A.3.
|
||||
## Hard Rules
|
||||
|
||||
1. Never commit secrets or credentials
|
||||
2. Never add logic to `localDb.ts`
|
||||
2. Never barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
|
||||
3. Never use `eval()` / `new Function()` / implied eval
|
||||
4. Never commit directly to `main`
|
||||
5. Never write raw SQL in routes — use `src/lib/db/` modules
|
||||
|
||||
16
Dockerfile
16
Dockerfile
@@ -103,25 +103,11 @@ RUN test -f package-lock.json \
|
||||
# node-gyp comes from npm's own bundled copy (deterministic, already in the image)
|
||||
# instead of `npx --yes`, which would install an arbitrary registry version
|
||||
# on-demand and run its lifecycle scripts (Sonar docker:S6505).
|
||||
#
|
||||
# tls-client-node (claude-web/grok-web/lmarena/perplexity-web TLS
|
||||
# impersonation) hits the same --ignore-scripts wall: its own postinstall.js
|
||||
# fetches a platform .so/.dylib/.dll from the bogdanfinn/tls-client GitHub
|
||||
# Releases API and is never invoked when npm ci skips lifecycle scripts. Unlike
|
||||
# better-sqlite3 above, that script never throws on failure — it only
|
||||
# `console.warn`s and exits 0 — so a rate-limited or offline build would
|
||||
# otherwise succeed silently with an empty bin/ and only fail at first request
|
||||
# in production (TlsClientUnavailableError, #7802). Run it explicitly here so
|
||||
# a broken/rate-limited fetch fails the BUILD loudly instead of shipping a
|
||||
# broken image.
|
||||
RUN --mount=type=cache,id=s/92ca8a61-c1ba-421f-a389-d48ac7258c2d-npm-cache,target=/root/.npm \
|
||||
npm ci --include=optional --no-audit --no-fund --legacy-peer-deps --ignore-scripts \
|
||||
&& (cd node_modules/better-sqlite3 \
|
||||
&& node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js rebuild) \
|
||||
&& node -e "require('better-sqlite3')(':memory:').close()" \
|
||||
&& node node_modules/tls-client-node/scripts/postinstall.js \
|
||||
&& (test -n "$(find node_modules/tls-client-node/bin -mindepth 1 -print -quit 2>/dev/null)" \
|
||||
|| (echo "tls-client-node native binary missing after postinstall — GitHub API fetch likely rate-limited or failed (#7802)" >&2 && exit 1))
|
||||
&& node -e "require('better-sqlite3')(':memory:').close()"
|
||||
|
||||
# Build with Turbopack (stable in Next 16, the repo default). The v3.8.27-era
|
||||
# TurbopackInternalError panic ("entered unreachable code: there must be a path to a
|
||||
|
||||
@@ -31,9 +31,9 @@ COPY scripts/dev/sync-env.mjs ./scripts/dev/sync-env.mjs
|
||||
# Fast Bun native package install
|
||||
RUN bun install --include=optional --quiet
|
||||
|
||||
# Fetch tls-client-node native binary if script exists
|
||||
RUN if [ -f "node_modules/tls-client-node/scripts/postinstall.js" ] && [ ! -d "node_modules/tls-client-node/bin" ]; then \
|
||||
bun node_modules/tls-client-node/scripts/postinstall.js || true; \
|
||||
# Compile native better-sqlite3 Node-API addon under Bun
|
||||
RUN if [ -d "node_modules/better-sqlite3" ]; then \
|
||||
(cd node_modules/better-sqlite3 && bunx node-gyp rebuild); \
|
||||
fi
|
||||
|
||||
# Smoke check native database driver used by Bun (bun:sqlite)
|
||||
|
||||
@@ -557,7 +557,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
|
||||
- **🧠 Memory you control** — off by default, opt-in int8 vector quantization + typed decay, per-request `x-omniroute-no-memory`. → [Memory](docs/frameworks/MEMORY.md)
|
||||
- **🛡️ Security** — prompt-injection guard on every LLM route (red-team suite), opt-in credential-masking guardrail (redacts leaked API keys/secrets in both directions), free DuckDuckGo last-resort web search, and an optional OIDC login gate for the dashboard (password login always stays available). → [Guardrails](docs/security/GUARDRAILS.md)
|
||||
- **🖼️ New endpoints** — `/v1/ocr` (Mistral OCR) and `/v1/audio/translations` (Whisper-style) round out the media surface. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Freepik, Adobe Firefly, Segmind, and speech providers such as ElevenLabs. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Magnific, Adobe Firefly, Segmind, and speech providers such as ElevenLabs. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🌍 Deployment & ops** — reverse-proxy `basePath`, browser-language auto-detect, per-key device tracking, root-less MITM trust, zh-TW localization. → [Environment](docs/reference/ENVIRONMENT.md)
|
||||
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **351-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
|
||||
- **📡 Routing transparency** — every response carries an `X-OmniRoute-Decision` header naming the strategy/provider/latency that served it, a new `cache-optimized` combo strategy + Auto-Combo `cacheAffinity` factor route repeat requests back to the connection holding the cached prefix, and a read-only `/v1/auto-combo/{channel}/candidates` endpoint exposes an `auto/*` channel's live candidate pool. → [Auto-Combo](docs/routing/AUTO-COMBO.md)
|
||||
@@ -612,7 +612,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
|
||||
<b>+ also works with</b> · Kiro · Command Code · Antigravity · Windsurf · AMP · <b>any OpenAI-compatible tool</b>
|
||||
</div>
|
||||
|
||||
<sub>📖 Per-tool setup for all 35 tools (26 CLI Code's + 9 CLI Agents) → [`docs/reference/CLI-TOOLS.md`](docs/reference/CLI-TOOLS.md) · 🧩 OpenCode plugin → [`@omniroute/opencode-provider`](https://www.npmjs.com/package/@omniroute/opencode-provider)</sub>
|
||||
<sub>📖 Per-tool setup for all 36 tools (26 CLI Code's + 10 CLI Agents) → [`docs/reference/CLI-TOOLS.md`](docs/reference/CLI-TOOLS.md) · 🧩 OpenCode plugin → [`@omniroute/opencode-provider`](https://www.npmjs.com/package/@omniroute/opencode-provider)</sub>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1202,7 +1202,7 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
|
||||
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>>=22.22.2 <23 || >=24.0.0 <27</code></td></tr>
|
||||
<tr><td nowrap><b>Language</b></td><td>TypeScript 6.0 — <b>100% TypeScript</b> across <code>src/</code> and <code>open-sse/</code> (zero <code>any</code> in core since v2.0)</td></tr>
|
||||
<tr><td nowrap><b>Framework</b></td><td>Next.js 16 + React 19 + Tailwind CSS 4</td></tr>
|
||||
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 120 domain modules, 166 migrations</td></tr>
|
||||
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 120 domain modules, 167 migrations</td></tr>
|
||||
<tr><td nowrap><b>Memory</b></td><td>SQLite FTS5 full-text + int8-quantized vector embeddings, typed decay</td></tr>
|
||||
<tr><td nowrap><b>Schemas</b></td><td>Zod 4 — MCP tool I/O validation + API contracts</td></tr>
|
||||
<tr><td nowrap><b>Protocols</b></td><td>MCP (stdio / HTTP / SSE) + A2A v0.3 (JSON-RPC 2.0 + SSE)</td></tr>
|
||||
|
||||
@@ -25,6 +25,31 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FO
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## wreq-js 3.0.0
|
||||
|
||||
OmniRoute distributes `wreq-js` and its seven platform-specific native addons from
|
||||
[`wreq-js@3.0.0`](https://www.npmjs.com/package/wreq-js/v/3.0.0).
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 will-work-for-meal
|
||||
Copyright (c) 2025 Oleksandr Herasymov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## blackwell-systems/gcf-typescript
|
||||
|
||||
The generic-profile codec in
|
||||
|
||||
@@ -16,7 +16,7 @@ export function register_combos(parent) {
|
||||
});
|
||||
tag.command("post-api-combos")
|
||||
.description("Create routing combo")
|
||||
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.action(async (opts, cmd) => {
|
||||
const gOpts = cmd.optsWithGlobals();
|
||||
let url = "/api/combos";
|
||||
@@ -44,7 +44,7 @@ export function register_combos(parent) {
|
||||
tag.command("put-api-combos-id-")
|
||||
.description("Update combo")
|
||||
.requiredOption("--id <id>", "")
|
||||
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.action(async (opts, cmd) => {
|
||||
const gOpts = cmd.optsWithGlobals();
|
||||
let url = "/api/combos/{id}";
|
||||
@@ -62,7 +62,7 @@ export function register_combos(parent) {
|
||||
tag.command("patch-api-combos-id-")
|
||||
.description("Update combo")
|
||||
.requiredOption("--id <id>", "")
|
||||
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.action(async (opts, cmd) => {
|
||||
const gOpts = cmd.optsWithGlobals();
|
||||
let url = "/api/combos/{id}";
|
||||
@@ -99,10 +99,17 @@ export function register_combos(parent) {
|
||||
});
|
||||
tag.command("post-api-combos-test")
|
||||
.description("Test a combo configuration")
|
||||
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
|
||||
.action(async (opts, cmd) => {
|
||||
const gOpts = cmd.optsWithGlobals();
|
||||
let url = "/api/combos/test";
|
||||
const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey });
|
||||
let body;
|
||||
if (opts.body) {
|
||||
body = opts.body.startsWith("@")
|
||||
? JSON.parse(readFileSync(opts.body.slice(1), "utf8"))
|
||||
: JSON.parse(opts.body);
|
||||
}
|
||||
const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey });
|
||||
const data = res.ok ? await res.json() : await res.text();
|
||||
emit(data, gOpts);
|
||||
});
|
||||
|
||||
@@ -93,6 +93,16 @@ export const CLI_TARGET_MANIFEST = Object.freeze({
|
||||
configure: true,
|
||||
runModel: null,
|
||||
}),
|
||||
"5dive": Object.freeze({
|
||||
// 5dive is a fleet manager, not a coding CLI: it points its own `claude`
|
||||
// agents at an endpoint. `omniroute run 5dive` would have nothing to
|
||||
// launch, so this is configure-only.
|
||||
description: "5dive (agent fleet)",
|
||||
aliases: Object.freeze(["fivedive", "5dive-cli"]),
|
||||
run: false,
|
||||
configure: true,
|
||||
runModel: null, // travels as the profile's ANTHROPIC_DEFAULT_*_MODEL
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ export const SETUP_MODULES = {
|
||||
cline: { module: "./setup-cline.mjs", exportName: "runSetupClineCommand" },
|
||||
continue: { module: "./setup-continue.mjs", exportName: "runSetupContinueCommand" },
|
||||
kilo: { module: "./setup-kilo.mjs", exportName: "runSetupKiloCommand" },
|
||||
"5dive": { module: "./setup-5dive.mjs", exportName: "runSetup5diveCommand" },
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,80 @@ function parseHeader(kv) {
|
||||
return { name: kv.slice(0, eq), value: kv.slice(eq + 1) };
|
||||
}
|
||||
|
||||
function getRootCommand(cmd) {
|
||||
let curr = cmd;
|
||||
while (curr.parent) curr = curr.parent;
|
||||
return curr;
|
||||
}
|
||||
|
||||
function resolveNodeEndpoint(opts, cmd) {
|
||||
if (opts.endpoint) {
|
||||
return { endpoint: opts.endpoint, apiFetchOpts: cmd.optsWithGlobals() };
|
||||
}
|
||||
if (opts.nodeUrl) {
|
||||
return { endpoint: opts.nodeUrl, apiFetchOpts: cmd.optsWithGlobals() };
|
||||
}
|
||||
|
||||
// Check if --base-url, --endpoint, or --node-url was explicitly passed after the subcommand
|
||||
const root = getRootCommand(cmd);
|
||||
const rawArgs = root.rawArgs || process.argv;
|
||||
const cmdName = cmd.name();
|
||||
|
||||
let subArgsStart = -1;
|
||||
for (let i = 0; i < rawArgs.length - 1; i++) {
|
||||
if (rawArgs[i] === "nodes" || rawArgs[i] === "provider-nodes") {
|
||||
if (rawArgs[i + 1] === cmdName) {
|
||||
subArgsStart = i + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let explicitSubcommandBaseUrl = undefined;
|
||||
let serverBaseUrl = undefined;
|
||||
|
||||
if (subArgsStart !== -1) {
|
||||
const preArgs = rawArgs.slice(0, subArgsStart);
|
||||
for (let i = 0; i < preArgs.length; i++) {
|
||||
if (preArgs[i] === "--base-url" && i + 1 < preArgs.length) {
|
||||
serverBaseUrl = preArgs[i + 1];
|
||||
} else if (preArgs[i].startsWith("--base-url=")) {
|
||||
serverBaseUrl = preArgs[i].slice("--base-url=".length);
|
||||
}
|
||||
}
|
||||
|
||||
const subArgs = rawArgs.slice(subArgsStart);
|
||||
for (let i = 0; i < subArgs.length; i++) {
|
||||
const arg = subArgs[i];
|
||||
if (
|
||||
(arg === "--base-url" || arg === "--endpoint" || arg === "--node-url") &&
|
||||
i + 1 < subArgs.length
|
||||
) {
|
||||
explicitSubcommandBaseUrl = subArgs[i + 1];
|
||||
} else if (
|
||||
arg.startsWith("--base-url=") ||
|
||||
arg.startsWith("--endpoint=") ||
|
||||
arg.startsWith("--node-url=")
|
||||
) {
|
||||
explicitSubcommandBaseUrl = arg.slice(arg.indexOf("=") + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (explicitSubcommandBaseUrl !== undefined) {
|
||||
const globals = cmd.optsWithGlobals?.() ?? {};
|
||||
const apiFetchOpts = { ...globals };
|
||||
if (serverBaseUrl) {
|
||||
apiFetchOpts.baseUrl = serverBaseUrl;
|
||||
} else {
|
||||
delete apiFetchOpts.baseUrl;
|
||||
}
|
||||
return { endpoint: explicitSubcommandBaseUrl, apiFetchOpts };
|
||||
}
|
||||
|
||||
return { endpoint: undefined, apiFetchOpts: cmd.optsWithGlobals() };
|
||||
}
|
||||
|
||||
const nodeSchema = [
|
||||
{ key: "id", header: "Node ID", width: 22 },
|
||||
{ key: "provider", header: "Provider", width: 16 },
|
||||
@@ -70,7 +144,8 @@ export function registerNodes(program) {
|
||||
nodes
|
||||
.command("add")
|
||||
.requiredOption("--provider <p>", t("nodes.add.provider"))
|
||||
.requiredOption("--endpoint <url>", t("nodes.add.baseUrl"))
|
||||
.option("--endpoint <url>", t("nodes.add.baseUrl"))
|
||||
.option("--base-url <url>", t("nodes.add.baseUrl"))
|
||||
.option("--name <n>", t("nodes.add.name"))
|
||||
.option("--weight <w>", t("nodes.add.weight"), parseInt, 100)
|
||||
.option("--region <r>", t("nodes.add.region"))
|
||||
@@ -81,9 +156,14 @@ export function registerNodes(program) {
|
||||
[]
|
||||
)
|
||||
.action(async (opts, cmd) => {
|
||||
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
|
||||
if (!endpoint) {
|
||||
process.stderr.write(`error: required option '--endpoint <url>' or '--base-url <url>' not specified\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
const body = {
|
||||
provider: opts.provider,
|
||||
baseUrl: opts.endpoint,
|
||||
baseUrl: endpoint,
|
||||
name: opts.name,
|
||||
weight: opts.weight,
|
||||
region: opts.region,
|
||||
@@ -91,7 +171,7 @@ export function registerNodes(program) {
|
||||
headers: opts.authHeader?.length ? opts.authHeader : undefined,
|
||||
};
|
||||
const res = await apiFetch("/api/provider-nodes", {
|
||||
...cmd.optsWithGlobals(),
|
||||
...apiFetchOpts,
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
@@ -99,24 +179,26 @@ export function registerNodes(program) {
|
||||
process.stderr.write(`Error: ${res.status}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
emit(await res.json(), cmd.optsWithGlobals());
|
||||
emit(await res.json(), apiFetchOpts);
|
||||
});
|
||||
|
||||
nodes
|
||||
.command("update <nodeId>")
|
||||
.option("--endpoint <url>", t("nodes.update.baseUrl"))
|
||||
.option("--base-url <url>", t("nodes.update.baseUrl"))
|
||||
.option("--name <n>", t("nodes.update.name"))
|
||||
.option("--weight <w>", t("nodes.update.weight"), parseInt)
|
||||
.option("--region <r>", t("nodes.update.region"))
|
||||
.option("--enabled <b>", t("nodes.update.enabled"), (v) => v === "true")
|
||||
.action(async (id, opts, cmd) => {
|
||||
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
|
||||
const body = {};
|
||||
if (opts.endpoint !== undefined) body.baseUrl = opts.endpoint;
|
||||
if (endpoint !== undefined) body.baseUrl = endpoint;
|
||||
for (const k of ["name", "weight", "region", "enabled"]) {
|
||||
if (opts[k] !== undefined) body[k] = opts[k];
|
||||
}
|
||||
const res = await apiFetch(`/api/provider-nodes/${id}`, {
|
||||
...cmd.optsWithGlobals(),
|
||||
...apiFetchOpts,
|
||||
method: "PUT",
|
||||
body,
|
||||
});
|
||||
@@ -124,7 +206,7 @@ export function registerNodes(program) {
|
||||
process.stderr.write(`Error: ${res.status}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
emit(await res.json(), cmd.optsWithGlobals());
|
||||
emit(await res.json(), apiFetchOpts);
|
||||
});
|
||||
|
||||
nodes
|
||||
@@ -145,19 +227,25 @@ export function registerNodes(program) {
|
||||
|
||||
nodes
|
||||
.command("validate")
|
||||
.requiredOption("--endpoint <url>", t("nodes.validate.baseUrl"))
|
||||
.option("--endpoint <url>", t("nodes.validate.baseUrl"))
|
||||
.option("--base-url <url>", t("nodes.validate.baseUrl"))
|
||||
.requiredOption("--provider <p>", t("nodes.validate.provider"))
|
||||
.action(async (opts, cmd) => {
|
||||
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
|
||||
if (!endpoint) {
|
||||
process.stderr.write(`error: required option '--endpoint <url>' or '--base-url <url>' not specified\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
const res = await apiFetch("/api/provider-nodes/validate", {
|
||||
...cmd.optsWithGlobals(),
|
||||
...apiFetchOpts,
|
||||
method: "POST",
|
||||
body: { baseUrl: opts.endpoint, provider: opts.provider },
|
||||
body: { baseUrl: endpoint, provider: opts.provider },
|
||||
});
|
||||
if (!res.ok) {
|
||||
process.stderr.write(`Error: ${res.status}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
emit(await res.json(), cmd.optsWithGlobals());
|
||||
emit(await res.json(), apiFetchOpts);
|
||||
});
|
||||
|
||||
nodes
|
||||
|
||||
@@ -66,6 +66,7 @@ import { registerSetupClaude } from "./setup-claude.mjs";
|
||||
import { registerSetupOpencode } from "./setup-opencode.mjs";
|
||||
import { registerSetupCline } from "./setup-cline.mjs";
|
||||
import { registerSetupKilo } from "./setup-kilo.mjs";
|
||||
import { registerSetup5dive } from "./setup-5dive.mjs";
|
||||
import { registerSetupContinue } from "./setup-continue.mjs";
|
||||
import { registerSetupCursor } from "./setup-cursor.mjs";
|
||||
import { registerSetupRoo } from "./setup-roo.mjs";
|
||||
@@ -152,6 +153,7 @@ export function registerCommands(program) {
|
||||
registerSetupOpencode(program);
|
||||
registerSetupCline(program);
|
||||
registerSetupKilo(program);
|
||||
registerSetup5dive(program);
|
||||
registerSetupContinue(program);
|
||||
registerSetupCursor(program);
|
||||
registerSetupRoo(program);
|
||||
|
||||
315
bin/cli/commands/setup-5dive.mjs
Normal file
315
bin/cli/commands/setup-5dive.mjs
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* omniroute setup-5dive — point a 5dive agent fleet at OmniRoute.
|
||||
*
|
||||
* 5dive (https://5dive.com) manages a fleet of long-running coding agents, each
|
||||
* one a systemd unit under its own Unix user. It is not itself a coding CLI, so
|
||||
* there is nothing for `omniroute run` to launch — this is a configure-only
|
||||
* target.
|
||||
*
|
||||
* Unlike the other recipes, 5dive does not read a config file out of $HOME. Its
|
||||
* credentials live in AUTH PROFILES under /var/lib/5dive/auth-profiles/<name>/,
|
||||
* and the supported way to write one is the CLI itself:
|
||||
*
|
||||
* 5dive agent auth set claude --provider=<id> --base-url=<url> \
|
||||
* --api-key=- --auth-profile=<name> --model=<slug>
|
||||
*
|
||||
* Four value flags, all four load-bearing (verified against 5dive-cli main,
|
||||
* 2026-08-27):
|
||||
* --provider `--base-url` is refused without it, rather than accepted
|
||||
* and silently dropped. `openai` here is 5dive's BYO id for
|
||||
* "a custom Anthropic-compatible endpoint", not a vendor
|
||||
* choice — override with --byo-provider.
|
||||
* --base-url OmniRoute's Anthropic surface, ROOT url with no /v1.
|
||||
* --auth-profile BYO credentials are profile-scoped; required for claude.
|
||||
* --model `openai` has no row in 5dive's built-in endpoint catalog,
|
||||
* so there are no per-tier model ids to inherit.
|
||||
*
|
||||
* The key is handed over on stdin (`--api-key=-`) so it never reaches argv.
|
||||
*
|
||||
* Two things this recipe cannot do for you, and says so instead of failing
|
||||
* obscurely:
|
||||
* 1. Writing an auth profile is root-only on the 5dive host. We re-exec
|
||||
* through sudo when we are not root (disable with --no-sudo).
|
||||
* 2. `agent auth set` writes the profile and restarts the agents bound to it,
|
||||
* but each seat also carries its OWN runtime model pin, and that pin wins
|
||||
* over the profile's ANTHROPIC_DEFAULT_*_MODEL. Pass --agent <name> (repeatable)
|
||||
* to pin the seats too; otherwise we print the command for them.
|
||||
*/
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { printHeading, printInfo, printSuccess, printError, createPrompt } from "../io.mjs";
|
||||
import { resolveActiveContext } from "../contexts.mjs";
|
||||
|
||||
const DEFAULT_PROFILE = "omniroute";
|
||||
|
||||
/** 5dive's `claude` BYO endpoint is the Anthropic surface ROOT — strip a trailing /v1. */
|
||||
function stripToRoot(url) {
|
||||
const s = String(url || "").replace(/\/+$/, "");
|
||||
return s.endsWith("/v1") ? s.slice(0, -3) : s;
|
||||
}
|
||||
|
||||
/** Resolve baseUrl (ROOT, no /v1) + apiKey from flags -> active context -> localhost. */
|
||||
export function resolveFivediveTarget(opts = {}) {
|
||||
let baseUrl;
|
||||
if (opts.remote) baseUrl = stripToRoot(opts.remote);
|
||||
else {
|
||||
try {
|
||||
baseUrl = stripToRoot(
|
||||
resolveActiveContext(opts.context ?? process.env.OMNIROUTE_CONTEXT)?.baseUrl
|
||||
);
|
||||
} catch {
|
||||
/* no context configured */
|
||||
}
|
||||
if (!baseUrl)
|
||||
baseUrl = `http://localhost:${Number(opts.port ?? process.env.PORT ?? 20128) || 20128}`;
|
||||
}
|
||||
let apiKey = opts.apiKey ?? opts["api-key"];
|
||||
if (!apiKey) {
|
||||
try {
|
||||
const c = resolveActiveContext(opts.context ?? process.env.OMNIROUTE_CONTEXT);
|
||||
apiKey = c?.accessToken || c?.apiKey;
|
||||
} catch {
|
||||
/* no context configured */
|
||||
}
|
||||
}
|
||||
if (!apiKey) apiKey = process.env.OMNIROUTE_API_KEY || "";
|
||||
return { baseUrl, apiKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* 5dive refuses a base URL before storing it, and the rule is not the obvious
|
||||
* one: the agent's key rides this URL on every request, so https:// is required
|
||||
* unless the host is loopback. Reproduce the check here so the operator gets the
|
||||
* reason at the point of choosing, not a validation error three commands later.
|
||||
*/
|
||||
export function validateFivediveBaseUrl(rawUrl) {
|
||||
const url = String(rawUrl || "");
|
||||
if (!url) return { ok: false, reason: "A base URL is required." };
|
||||
if (url.startsWith("https://")) return { ok: true };
|
||||
if (!url.startsWith("http://")) {
|
||||
return { ok: false, reason: `Unsupported scheme in '${url}' (expected http:// or https://).` };
|
||||
}
|
||||
let host = url.slice("http://".length);
|
||||
host = host.split("/")[0].split("?")[0];
|
||||
host = host.startsWith("[") ? `${host.slice(0, host.indexOf("]"))}]` : host.split(":")[0];
|
||||
if (host === "127.0.0.1" || host === "localhost" || host === "[::1]") return { ok: true };
|
||||
return {
|
||||
ok: false,
|
||||
reason:
|
||||
`5dive accepts http:// only for a loopback host; '${host}' is off-box, so the agent's ` +
|
||||
`API key would travel in plaintext. Serve OmniRoute over https:// and pass ` +
|
||||
`--remote https://${host}...`,
|
||||
};
|
||||
}
|
||||
|
||||
/** Argv for the profile write. The key is NOT here — it goes in on stdin. */
|
||||
export function buildFivediveAuthArgs({ baseUrl, profile, model, provider = "openai" }) {
|
||||
return [
|
||||
"agent",
|
||||
"auth",
|
||||
"set",
|
||||
"claude",
|
||||
`--provider=${provider}`,
|
||||
`--base-url=${baseUrl}`,
|
||||
"--api-key=-",
|
||||
`--auth-profile=${profile}`,
|
||||
`--model=${model}`,
|
||||
];
|
||||
}
|
||||
|
||||
/** Argv for one seat's runtime model pin, which outranks the profile's env defaults. */
|
||||
export function buildFivedivePinArgs(agent, model) {
|
||||
return ["agent", "config", agent, "set", `model=${model}`];
|
||||
}
|
||||
|
||||
/** Prepend sudo when the profile write needs root and we do not have it. */
|
||||
export function withPrivilege(bin, args, { isRoot, useSudo }) {
|
||||
if (isRoot || !useSudo) return [bin, args];
|
||||
return ["sudo", [bin, ...args]];
|
||||
}
|
||||
|
||||
function quote(arg) {
|
||||
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(arg) ? arg : `'${String(arg).replace(/'/g, "'\\''")}'`;
|
||||
}
|
||||
|
||||
/** Render argv the way an operator would type it. */
|
||||
export function renderCommand(bin, args) {
|
||||
return [bin, ...args].map(quote).join(" ");
|
||||
}
|
||||
|
||||
function run(bin, args, stdinPayload) {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(bin, args, {
|
||||
// sudo reads its password straight from the tty, so stdin stays free for
|
||||
// the API key.
|
||||
stdio: [stdinPayload === undefined ? "inherit" : "pipe", "inherit", "inherit"],
|
||||
});
|
||||
child.on("error", (e) => resolve({ code: 1, error: e }));
|
||||
child.on("close", (code) => resolve({ code: code ?? 1 }));
|
||||
if (stdinPayload !== undefined && child.stdin) {
|
||||
child.stdin.end(stdinPayload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchModelIds(baseUrl, apiKey) {
|
||||
try {
|
||||
const headers = { "Content-Type": "application/json" };
|
||||
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
||||
const res = await fetch(`${baseUrl}/v1/models`, { headers, signal: AbortSignal.timeout(8000) });
|
||||
if (!res.ok) return [];
|
||||
const body = await res.json();
|
||||
const list = Array.isArray(body) ? body : (body.data ?? body.models ?? []);
|
||||
return list.map((m) => (typeof m === "string" ? m : m?.id)).filter(Boolean);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function agentList(opts) {
|
||||
const raw = opts.agent ?? opts.agents ?? [];
|
||||
return (Array.isArray(raw) ? raw : [raw]).map((a) => String(a).trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
export async function runSetup5diveCommand(opts = {}) {
|
||||
const { baseUrl, apiKey } = resolveFivediveTarget(opts);
|
||||
const dryRun = Boolean(opts.dryRun ?? opts["dry-run"]);
|
||||
const bin = opts.fivediveBin ?? opts["fivedive-bin"] ?? process.env.CLI_5DIVE_BIN ?? "5dive";
|
||||
const profile = String(opts.authProfile ?? opts["auth-profile"] ?? opts.name ?? DEFAULT_PROFILE);
|
||||
// NOT `opts.provider`: the `configure` picker uses that flag for the
|
||||
// OmniRoute model provider to filter on, and it reaches setup recipes
|
||||
// verbatim. The 5dive BYO id is its own flag.
|
||||
const provider = String(opts.byoProvider ?? opts["byo-provider"] ?? "openai");
|
||||
const agents = agentList(opts);
|
||||
|
||||
printHeading("OmniRoute -> 5dive (claude BYO endpoint)");
|
||||
printInfo(`Server: ${baseUrl}`);
|
||||
printInfo(`Profile: ${profile}`);
|
||||
|
||||
const urlCheck = validateFivediveBaseUrl(baseUrl);
|
||||
if (!urlCheck.ok) {
|
||||
printError(urlCheck.reason);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// 5dive needs one explicit model id: `openai` has no catalog row, so there
|
||||
// are no per-tier defaults to fall back to.
|
||||
let model = opts.model;
|
||||
if (!model) {
|
||||
const ids = await fetchModelIds(baseUrl, apiKey);
|
||||
if (ids.length && !opts.yes) {
|
||||
printInfo(`Examples: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? " …" : ""}`);
|
||||
printInfo("A combo id works here too — that is how you get failover across providers.");
|
||||
const prompt = createPrompt();
|
||||
try {
|
||||
model = await prompt.ask("Model or combo id for the 5dive agents");
|
||||
} finally {
|
||||
prompt.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!model) {
|
||||
printError("A model is required. Pass --model <id> (5dive has no model auto-discovery here).");
|
||||
return 2;
|
||||
}
|
||||
if (!apiKey) {
|
||||
printError("An OmniRoute API key is required. Pass --api-key, or set OMNIROUTE_API_KEY.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const isRoot = typeof process.getuid === "function" ? process.getuid() === 0 : false;
|
||||
const useSudo = (opts.sudo ?? true) !== false;
|
||||
const authArgs = buildFivediveAuthArgs({ baseUrl, profile, model, provider });
|
||||
const [authBin, authArgv] = withPrivilege(bin, authArgs, { isRoot, useSudo });
|
||||
|
||||
if (dryRun) {
|
||||
printInfo("\n[dry-run] would run:");
|
||||
printInfo(` ${renderCommand(authBin, authArgv)}`);
|
||||
printInfo(" (the API key is written to that command's stdin, never to argv)");
|
||||
for (const agent of agents) {
|
||||
const [pinBin, pinArgv] = withPrivilege(bin, buildFivedivePinArgs(agent, model), {
|
||||
isRoot,
|
||||
useSudo,
|
||||
});
|
||||
printInfo(` ${renderCommand(pinBin, pinArgv)}`);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!isRoot && !useSudo) {
|
||||
printError(
|
||||
"Writing a 5dive auth profile needs root on the 5dive host. Re-run as root, drop --no-sudo, " +
|
||||
"or run this by hand:"
|
||||
);
|
||||
printInfo(` ${renderCommand(bin, authArgs)}`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const authResult = await run(authBin, authArgv, apiKey);
|
||||
if (authResult.error?.code === "ENOENT") {
|
||||
printError(
|
||||
`Could not find the '${bin}' CLI on this machine. 5dive's verbs run ON the fleet host — ` +
|
||||
"run this there, or point at the binary with --fivedive-bin."
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
if (authResult.code !== 0) {
|
||||
printError(`'${bin} agent auth set' exited ${authResult.code}.`);
|
||||
return authResult.code;
|
||||
}
|
||||
printSuccess(`Auth profile '${profile}' now points at ${baseUrl}`);
|
||||
|
||||
// The profile carries ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU}_MODEL, but each
|
||||
// seat's own runtime pin outranks it — a seat still pinned to a stock model id
|
||||
// fails its first turn with "There's an issue with the selected model".
|
||||
for (const agent of agents) {
|
||||
const [pinBin, pinArgv] = withPrivilege(bin, buildFivedivePinArgs(agent, model), {
|
||||
isRoot,
|
||||
useSudo,
|
||||
});
|
||||
const pinResult = await run(pinBin, pinArgv);
|
||||
if (pinResult.code !== 0) {
|
||||
printError(`Could not pin agent '${agent}' to '${model}' (exit ${pinResult.code}).`);
|
||||
return pinResult.code;
|
||||
}
|
||||
printSuccess(`Agent '${agent}' pinned to ${model}`);
|
||||
}
|
||||
|
||||
if (!agents.length) {
|
||||
printInfo("\nEach seat also carries its own runtime model pin, and it beats the profile:");
|
||||
printInfo(` ${renderCommand(bin, buildFivedivePinArgs("<agent>", model))}`);
|
||||
printInfo("Re-run with --agent <name> to have this command apply it for you.");
|
||||
}
|
||||
printInfo("\nBind a seat to the profile at creation time with:");
|
||||
printInfo(` ${renderCommand(bin, ["agent", "create", "<name>", `--auth-profile=${profile}`])}`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function registerSetup5dive(program) {
|
||||
program
|
||||
.command("setup-5dive")
|
||||
.description(
|
||||
"Point a 5dive agent fleet's claude seats at OmniRoute (writes a 5dive auth profile)"
|
||||
)
|
||||
.option("--port <port>", "Local OmniRoute port (ignored when --remote is set)", "20128")
|
||||
.option("--remote <url>", "Remote OmniRoute URL, e.g. https://omniroute.example.com")
|
||||
.option("--context <name>", "Named local/remote context")
|
||||
.option("--api-key <key>", "OmniRoute API key (defaults to the active context/env)")
|
||||
.option("--model <id>", "OmniRoute model or combo id the agents should use")
|
||||
.option("--byo-provider <id>", "5dive BYO provider id (default: openai)", "openai")
|
||||
.option("--auth-profile <name>", "5dive auth profile to write", DEFAULT_PROFILE)
|
||||
.option(
|
||||
"--agent <name>",
|
||||
"Also pin this agent's runtime model (repeatable)",
|
||||
(value, previous) => [...(previous || []), value],
|
||||
[]
|
||||
)
|
||||
.option("--fivedive-bin <path>", "Path to the 5dive binary (default: 5dive on PATH)")
|
||||
.option("--no-sudo", "Do not re-exec through sudo when not running as root")
|
||||
.option("--yes", "Non-interactive: do not prompt (requires --model)")
|
||||
.option("--dry-run", "Print the commands without running them")
|
||||
.action(async (opts) => {
|
||||
const code = await runSetup5diveCommand(opts);
|
||||
if (code !== 0) process.exit(code);
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { printHeading, printInfo, printSuccess, printError } from "../io.mjs";
|
||||
import { printHeading, printInfo, printSuccess, printError, printWarning } from "../io.mjs";
|
||||
import { homedir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -6,6 +6,7 @@ import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import { t } from "../i18n.mjs";
|
||||
import { npmBin, npmExecOptions } from "../npm-exec.mjs";
|
||||
import { readPidFile, isPidRunning } from "../utils/pid.mjs";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
@@ -79,6 +80,39 @@ export async function createBackup() {
|
||||
}
|
||||
}
|
||||
|
||||
// #11885: `--apply` installs the new files (npm install -g) and re-reads
|
||||
// package.json from disk to confirm it, but a long-lived server process keeps
|
||||
// serving whatever it loaded at its last start — Node caches a `require()`d
|
||||
// package.json per resolved path for the life of the process. A later
|
||||
// `omniroute update` then correctly reports "already up to date" (the files
|
||||
// ARE current) while the running server is still stale, matching the reported
|
||||
// symptom. `--apply` never restarted anything and its success message ("Run
|
||||
// `omniroute --version` to verify.") implied the update was already live.
|
||||
//
|
||||
// `restart.mjs`'s `runRestartCommand()` stops then re-spawns the server in the
|
||||
// foreground (via `serve.mjs::runServe`), which can block the calling terminal
|
||||
// and is a materially bigger behavior change than this fix warrants to invoke
|
||||
// unconditionally and unattended from `--apply`. Instead, detect whether a
|
||||
// CLI-managed server is currently running (the same PID file `stop.mjs`/
|
||||
// `restart.mjs` already trust) and print an explicit, prominent instruction —
|
||||
// honest about what did and didn't happen — rather than silently assuming.
|
||||
export async function isServerProcessRunning(deps = { readPidFile, isPidRunning }) {
|
||||
const pid = deps.readPidFile("server");
|
||||
return Boolean(pid && deps.isPidRunning(pid));
|
||||
}
|
||||
|
||||
export async function printPostApplyGuidance(latest, deps = { readPidFile, isPidRunning }) {
|
||||
const running = await isServerProcessRunning(deps);
|
||||
if (running) {
|
||||
printWarning(`Files updated to ${latest}, but the running server is still on the old version.`);
|
||||
printInfo(" Run `omniroute restart` now to apply this update.");
|
||||
} else {
|
||||
printInfo(`No running OmniRoute server was detected via the CLI's PID file.`);
|
||||
printInfo(` Start it with \`omniroute serve\` (or restart your existing process) to run ${latest}.`);
|
||||
}
|
||||
printInfo("`omniroute --version` will keep reporting the old version until the process restarts.");
|
||||
}
|
||||
|
||||
export function registerUpdate(program) {
|
||||
program
|
||||
.command("update")
|
||||
@@ -210,8 +244,8 @@ export async function runUpdateCommand(opts = {}) {
|
||||
console.log(" or reorder PATH so the global bin comes first.");
|
||||
return 1;
|
||||
}
|
||||
printSuccess(`Updated to version ${latest}`);
|
||||
printInfo("Run `omniroute --version` to verify.");
|
||||
printSuccess(`Installed omniroute@${latest} to disk.`);
|
||||
await printPostApplyGuidance(latest);
|
||||
return 0;
|
||||
} catch (err) {
|
||||
printError(`Update failed: ${err.message}`);
|
||||
|
||||
@@ -81,3 +81,7 @@ export function printInfo(message) {
|
||||
export function printError(message) {
|
||||
console.log(`\x1b[31m✖ ${message}\x1b[0m`);
|
||||
}
|
||||
|
||||
export function printWarning(message) {
|
||||
console.log(`\x1b[33m⚠ ${message}\x1b[0m`);
|
||||
}
|
||||
|
||||
@@ -100,31 +100,66 @@ export async function waitForServer(port, timeout = 60000) {
|
||||
// - "hanging": the request timed out waiting for any response — the
|
||||
// process accepted the TCP connection but never answered (#6800).
|
||||
// - "not-listening": nothing is accepting connections on the port at all.
|
||||
// #11766: probe both IPv4 and IPv6 loopback to handle servers listening on
|
||||
// either family (or both).
|
||||
async function pollHealthOnce(port) {
|
||||
try {
|
||||
const res = await fetch(`http://127.0.0.1:${port}/api/monitoring/health`, {
|
||||
signal: AbortSignal.timeout(2000),
|
||||
});
|
||||
return res.ok ? "ready" : "fast-reject";
|
||||
} catch (err) {
|
||||
if (err?.name === "TimeoutError") return "hanging";
|
||||
const listening = await isPortListening(port).catch(() => false);
|
||||
return listening ? "fast-reject" : "not-listening";
|
||||
}
|
||||
const hosts = ["127.0.0.1", "::1"];
|
||||
const outcomes = [];
|
||||
|
||||
// Probe both loopback families concurrently
|
||||
const results = await Promise.all(
|
||||
hosts.map(async (host) => {
|
||||
try {
|
||||
const res = await fetch(`http://${host}:${port}/api/monitoring/health`, {
|
||||
signal: AbortSignal.timeout(2000),
|
||||
});
|
||||
return { host, outcome: res.ok ? "ready" : "fast-reject" };
|
||||
} catch (err) {
|
||||
const outcome = err?.name === "TimeoutError" ? "hanging" : "error";
|
||||
return { host, outcome };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
outcomes.push(...results.map((r) => r.outcome));
|
||||
|
||||
// If either family is ready, the server is ready
|
||||
if (outcomes.includes("ready")) return "ready";
|
||||
|
||||
// If either family is fast-reject, treat as fast-reject
|
||||
// (TCP is listening and rejecting, just route not ready yet)
|
||||
if (outcomes.includes("fast-reject")) return "fast-reject";
|
||||
|
||||
// If either family is hanging, server accepted TCP but not answering
|
||||
// (still booting, must not report as ready per #6800)
|
||||
if (outcomes.includes("hanging")) return "hanging";
|
||||
|
||||
// Both families failed — check if either port is actually listening
|
||||
// If listening, then errors above are route-level (fast-reject case)
|
||||
const listening = await isPortListening(port).catch(() => false);
|
||||
return listening ? "fast-reject" : "not-listening";
|
||||
}
|
||||
|
||||
async function isPortListening(port) {
|
||||
const net = await import("node:net");
|
||||
return new Promise((resolve) => {
|
||||
const socket = net.connect({ host: "127.0.0.1", port, timeout: 1000 });
|
||||
const finish = (ok) => {
|
||||
try {
|
||||
socket.destroy();
|
||||
} catch {}
|
||||
resolve(ok);
|
||||
};
|
||||
socket.once("connect", () => finish(true));
|
||||
socket.once("error", () => finish(false));
|
||||
socket.once("timeout", () => finish(false));
|
||||
});
|
||||
// #11766: check both IPv4 and IPv6 loopback. Return true if either is listening.
|
||||
const hosts = ["127.0.0.1", "::1"];
|
||||
const results = await Promise.all(
|
||||
hosts.map(
|
||||
(host) =>
|
||||
new Promise((resolve) => {
|
||||
const socket = net.connect({ host, port, timeout: 1000 });
|
||||
const finish = (ok) => {
|
||||
try {
|
||||
socket.destroy();
|
||||
} catch {}
|
||||
resolve(ok);
|
||||
};
|
||||
socket.once("connect", () => finish(true));
|
||||
socket.once("error", () => finish(false));
|
||||
socket.once("timeout", () => finish(false));
|
||||
})
|
||||
)
|
||||
);
|
||||
return results.some((ok) => ok);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- feat(api): add an opt-in `modelVisibilityAllowlist`/`modelVisibilityDenylist` settings pair to curate exactly which models `/v1/models` advertises, mirrored into every `auto/*` combo candidate pool so a denied model cannot be routed to via combo selection either (#11481)
|
||||
@@ -0,0 +1 @@
|
||||
- **feat(guardrails):** enforce a bounded, deterministic contract for Video Bridge transcripts — 256 cues, 4096 input code units and 4 KiB UTF-8 per cue, 64 KiB total text, malformed-Unicode rejection, focus-window scoping, cross-source reconciliation with contributing-source metadata, and a structural provenance trust boundary so caller JSON can never self-assert `embedded`/`audio-bridge` provenance ([#11652](https://github.com/diegosouzapw/OmniRoute/issues/11652))
|
||||
@@ -0,0 +1 @@
|
||||
- **feat(video):** orchestrate optional Video Bridge audio extraction and Audio Bridge STT behind a dual opt-in (operator setting AND per-request signal) — a new loopback-only broker `mode=audio` operation shares the frame path's exact process queue, deadline, AbortSignal, and byte budgets to extract a bounded mono 16 kHz PCM WAV from the same already-downloaded video, then reuses the existing Audio Bridge transcription boundary; provider segment timing is preserved when available and marked coarse otherwise, and every failure degrades to a visual-only-safe partial instead of throwing (#11654).
|
||||
@@ -0,0 +1,6 @@
|
||||
- Add a tenant-bound Video Bridge drill-down lifecycle on top of the existing secure cache
|
||||
substrate: opaque hashed handles (never raw session/video identifiers), preview/standard/detail
|
||||
multiresolution variants resampled on read, response pagination capped at 8 frames and 32 MiB,
|
||||
and a new authenticated `/api/v1/video-bridge/drilldown` consumer route that stays disabled for
|
||||
remote access by default and denies cross-key access with the same response as a nonexistent
|
||||
handle (no existence oracle).
|
||||
@@ -0,0 +1 @@
|
||||
- **test(video):** Add the Video Bridge FU-07/FU-09 promotion-evidence harness (#11656) — a frozen Zod manifest schema covering the 8 required scenario kinds (static scenes, rapid cuts, late facts, fades, blur, small text, close events, visual prompt injection) with a minimum of 3 repetitions per case, deterministic declarative fixture recipes (`videoBridgePromotionFixtures.ts`), a pure medians/p95 metrics aggregator, a pure FU-07/FU-09 promotion-verdict evaluator applying the ticket's exact thresholds (missing token usage always holds), a digest-only persistence layer that never retains raw media or raw model responses, and a versioned per-model promotion allowlist shipped empty with every model defaulting to `hold`. The FU-07/FU-09 promotion verdicts themselves remain HOLD — they require a real evidence run against real models on VPS 192.168.0.15.
|
||||
@@ -0,0 +1 @@
|
||||
- **feat(video bridge):** "embedded" transcript provenance can now be legitimately earned instead of merely asserted — a bounded, allowlisted (`mov_text`/`subrip`/`webvtt`) subtitle probe runs through the loopback-only Video Bridge broker (at most 2 streams, 10s subdeadline bounded by the request deadline, 256 KiB output, 4096-code-unit lines), normalized through a bounded, ReDoS-safe WebVTT parser and Zod-validated end to end. The adapter always resolves to an explicit `success`/`absent`/`transient_failure` outcome — a subtitle failure never breaks the visual description path, and only a fingerprint-verified broker response (never a caller-declared label) can produce embedded cues (#11659).
|
||||
1
changelog.d/features/11801-zai-glm-53-flash.md
Normal file
1
changelog.d/features/11801-zai-glm-53-flash.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(zai):** add GLM-5.3-Flash Coding Plan support (1M context, 128K output, vision, `low|high|max` reasoning) and route `zai` GLM-5.3-family API-key traffic through the OpenAI-compatible Coding Plan endpoint with native thinking defaults ([#11801](https://github.com/diegosouzapw/OmniRoute/pull/11801)) — thanks @Neuron-Mr-White
|
||||
1
changelog.d/features/11852-5dive-configure-target.md
Normal file
1
changelog.d/features/11852-5dive-configure-target.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(nodejs):** add `5dive` as a `configure` target — `omniroute configure 5dive` / `omniroute setup-5dive` write a 5dive auth profile that points an agent fleet's `claude` seats at OmniRoute, with the root-only write, the loopback-vs-`https` endpoint rule and the per-seat model pin handled explicitly ([#11852](https://github.com/diegosouzapw/OmniRoute/pull/11852))
|
||||
1
changelog.d/features/11903-usage-fetch-capability.md
Normal file
1
changelog.d/features/11903-usage-fetch-capability.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(providers):** the provider plugin manifest now advertises a `usage-fetch` capability for the 40 providers that have a wired usage/quota fetcher, so external dashboards can read it from `GET /api/v1/provider-plugin-manifest` instead of parsing `open-sse/services/usage.ts` after every release. Discovery only — no new fetcher, no quota change, and the Dashboard quota widget stays gated by `USAGE_SUPPORTED_PROVIDERS`. `USAGE_FETCHER_PROVIDERS` moved to a zero-dependency leaf (`open-sse/services/usage/fetcherProviders.ts`) and is re-exported from `services/usage.ts`, keeping the manifest module a light leaf instead of pulling the ~490-module usage dispatcher into the manifest route. ([#11903](https://github.com/diegosouzapw/OmniRoute/pull/11903)) — thanks @maxmad64bis
|
||||
1
changelog.d/features/11906-omniroute-plugins-dir.md
Normal file
1
changelog.d/features/11906-omniroute-plugins-dir.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(plugins):** `OMNIROUTE_PLUGINS_DIR` sets the directory the runtime plugin scanner reads — and the root the plugin manager installs into — overriding the `HOME`-derived default, so a Docker/K8s deployment can point straight at its bind-mounted plugin tree instead of moving `HOME` just to relocate the scan path. An image that exports no home no longer scans `/tmp/.omniroute/plugins` in silence: the resolved directory is logged once at startup as `scanner.dir_resolved`, naming the input that won. Unset, behaviour is unchanged. Distinct from the CLI-only `OMNIROUTE_PLUGIN_PATH`, which finds `omniroute-cmd-*` command packages and never reached this scanner ([#11906](https://github.com/diegosouzapw/OmniRoute/pull/11906)) — thanks @amaleta
|
||||
@@ -0,0 +1 @@
|
||||
- **feat(leases):** add an explicit owner-authenticated status action that returns only the active lease's privacy-safe configured connection and provider labels, with generation fencing and no credential or internal-id disclosure ([#11910](https://github.com/diegosouzapw/OmniRoute/pull/11910)) — thanks @KaspaPulse
|
||||
1
changelog.d/features/dashboard-cache-percentage.md
Normal file
1
changelog.d/features/dashboard-cache-percentage.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(dashboard):** display clamped `[0, 100]%` cached input token ratio in request logs table ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER))
|
||||
1
changelog.d/features/disable-thinking-level-variants.md
Normal file
1
changelog.d/features/disable-thinking-level-variants.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(catalog):** add `OMNIROUTE_DISABLE_THINKING_LEVEL_VARIANTS` feature flag to optionally filter out thinking level variants from model catalog ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER))
|
||||
11
changelog.d/features/log-export-destinations.md
Normal file
11
changelog.d/features/log-export-destinations.md
Normal file
@@ -0,0 +1,11 @@
|
||||
- **feat(dashboard):** continuously export call logs to external analytics stores. A pluggable
|
||||
destination registry ships the full Logs-tab record set on an hourly `JobRegistry` cron, with
|
||||
a persisted per-destination cursor, batched inserts, a config UI rendered from each
|
||||
destination's own field descriptors, and a REST layer (`/api/log-export/*`) for CRUD, a
|
||||
connection test, and an on-demand run. A destination can opt into `includeBodies` to also ship
|
||||
the request and response payloads shown in the Logs detail pane, including the client and
|
||||
provider views of each call; this is off by default, and payloads inherit the dashboard's PII
|
||||
sanitisation, secret redaction and `noLog` handling. Google BigQuery is the first destination,
|
||||
using a service-account key stored encrypted at rest and streaming inserts keyed by call-log id,
|
||||
into a table that is day-partitioned on `timestamp` and clustered on `api_key_name`, `provider`,
|
||||
`model` and `status`.
|
||||
1
changelog.d/features/perplexity-agent-provider.md
Normal file
1
changelog.d/features/perplexity-agent-provider.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(providers):** add a Perplexity Agent API provider (`perplexity-agent` / `pplx-agent`) for Perplexity `/v1/responses`, including the documented Anthropic, OpenAI, Google, xAI, DeepSeek, Z.AI, Moonshot/Kimi, NVIDIA, and Perplexity model IDs plus Anthropic-model `max_output_tokens` compatibility.
|
||||
1
changelog.d/fixes/0000-provider-icon-zero-size.md
Normal file
1
changelog.d/fixes/0000-provider-icon-zero-size.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(dashboard):** Keep local and theme-aware provider SVG icons at a definite layout size so Chromium does not collapse them to 0×0 after the v3.8.50 image-rendering change ([#12054](https://github.com/diegosouzapw/OmniRoute/pull/12054)) — thanks @ponkcore
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(kie):** reroute `flux/kontext` off the KIE Market `createTask` flow — it is catalogued with `isMarket: true` but has no Market catalog page, so KIE rejected it with "model name not supported"; it now hits the dedicated `POST /api/v1/flux/kontext/generate` / `GET /api/v1/flux/kontext/record-info` endpoints instead (#11296).
|
||||
1
changelog.d/fixes/11500-arena-elo-log-dedup.md
Normal file
1
changelog.d/fixes/11500-arena-elo-log-dedup.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(db): rate-limit repeated Arena ELO leaderboard fetch-failure warnings instead of logging one per sync attempt (#11500)
|
||||
@@ -0,0 +1,5 @@
|
||||
- Dropped the stale-`.eslintcache` `restore-keys` fallback from both "Restore ESLint file
|
||||
cache" steps in `ci.yml`, so the blocking `Lint` job can no longer be served per-file
|
||||
verdicts computed under a different lint config, suppressions file or lockfile. `quality.yml`
|
||||
had already dropped it in #11963; `ci.yml` — the workflow that actually gates PRs — had not
|
||||
(#11600).
|
||||
@@ -0,0 +1 @@
|
||||
- fix(ci): pass `--pass-on-unpruned-suppressions` in `run-eslint-json.mjs` so the CI Lint job no longer fails when a suppression is merely orphaned by a genuine fix, mirroring the identical fix already in `validate-release-green.mjs` (#11600)
|
||||
1
changelog.d/fixes/11704-prepublish-npx-cmd-win32.md
Normal file
1
changelog.d/fixes/11704-prepublish-npx-cmd-win32.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(build):** `prepublish.ts` bundles the ChatGPT Web (Codex) MCP bridge through `runBuildTool()` instead of spawning `npx.cmd` raw, fixing the build crash on Node ≥ 20/Windows where `.cmd` shims cannot be spawned without a shell (EINVAL) ([#11704](https://github.com/diegosouzapw/OmniRoute/issues/11704))
|
||||
@@ -0,0 +1 @@
|
||||
- fix(codex): keep `parallel_tool_calls:false` on the translated Codex Responses Lite path (#11707)
|
||||
1
changelog.d/fixes/11747-browser-pool-lockfile-sync.md
Normal file
1
changelog.d/fixes/11747-browser-pool-lockfile-sync.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(packages/browser-pool):** regenerate `package-lock.json` so the `packages/browser-pool` workspace's locked `playwright`/`@types/node` (and transitives) match its `package.json` specs, fixing cache-only/offline installs (`npm ci --offline`, Nix `buildNpmPackage`) that previously failed with `ENOTCACHED` ([#11747](https://github.com/diegosouzapw/OmniRoute/issues/11747)) — thanks @benjaminkitt
|
||||
1
changelog.d/fixes/11758-usage-refresh-exclusive-lease.md
Normal file
1
changelog.d/fixes/11758-usage-refresh-exclusive-lease.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(usage):** quota and usage refresh no longer 409 when an exclusive lease reserves the connection ([#11758](https://github.com/diegosouzapw/OmniRoute/pull/11758)) — thanks @TheDemonTuan
|
||||
@@ -0,0 +1 @@
|
||||
- fix(cli): stop prepublish from re-rebuilding the already-built ESM-only opencode-plugin dist (#11787)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(sse): set X-OmniRoute-Selected-Connection-Id on successful combo dispatches so downstream consumers stop falling back to an empty connection id (#11810)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(providers):** Antigravity's dynamic mitmAlias table no longer routes `gemini-3.7-flash-{high,medium,low}` to a literal tier-suffixed upstream id just because one connected account's own discovery listed it directly — those display ids always resolve through the safe `gemini-3.7-flash-tiered` static alias, so one account's Google-provisioned access no longer 404s every sibling account of the provider ([#11824](https://github.com/diegosouzapw/OmniRoute/issues/11824), [#11651](https://github.com/diegosouzapw/OmniRoute/issues/11651))
|
||||
1
changelog.d/fixes/11861-nous-hermes-405b-label.md
Normal file
1
changelog.d/fixes/11861-nous-hermes-405b-label.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(config):** Nous Research's `Hermes-4-405B` model now displays as "Hermes 4 405B (Nous Research)" in both the provider registry and the free-model catalog, instead of the mislabelled "Hermes 4 7B" ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825
|
||||
1
changelog.d/fixes/11861-nous-tags-user-injection.md
Normal file
1
changelog.d/fixes/11861-nous-tags-user-injection.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(provider/nous):** inject required user= tag into Nous Research inference requests to resolve upstream 400 "missing tags" error ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825
|
||||
10
changelog.d/fixes/11863-native-dep-preflight.md
Normal file
10
changelog.d/fixes/11863-native-dep-preflight.md
Normal file
@@ -0,0 +1,10 @@
|
||||
- **fix(build):** `npm run build` now fails in one second with a named package and a
|
||||
copy-pasteable fix when npm silently drops an externalised optional native
|
||||
dependency, instead of dying four minutes in with `Module not found: Can't resolve
|
||||
'better-sqlite3'` ([#11863](https://github.com/diegosouzapw/OmniRoute/pull/11863)) —
|
||||
thanks @ujjawalkaushik1110
|
||||
- **fix(install):** `postinstall` no longer throws `ReferenceError: isAndroid is not
|
||||
defined` — failing the whole `npm install` — when the `better-sqlite3` rebuild
|
||||
fallback times out; the manual-fix guidance is reachable again
|
||||
([#11863](https://github.com/diegosouzapw/OmniRoute/pull/11863)) — thanks
|
||||
@ujjawalkaushik1110
|
||||
1
changelog.d/fixes/11885-update-restart-live-process.md
Normal file
1
changelog.d/fixes/11885-update-restart-live-process.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(cli):** `omniroute update --apply` now tells you explicitly whether a running server was detected and, if so, that you must run `omniroute restart` to apply the update — it never restarted anything and previously implied the update was already live once files were installed. The dashboard's npm-mode Update flow (`/api/system/version`) now tries OmniRoute's own PID-file-managed supervisor before falling back to pm2, and reports an honest "restart required" step instead of a silent pm2-only "skipped" that read like a completed update. The server-side latest-version lookup backing the dashboard's update banner also gained `--prefer-online`, closing the same stale-npm-cache class already fixed in the CLI's own copy for #4376 ([#11885](https://github.com/diegosouzapw/OmniRoute/issues/11885)).
|
||||
1
changelog.d/fixes/11911-lkgp-stale-pin-exhaustion.md
Normal file
1
changelog.d/fixes/11911-lkgp-stale-pin-exhaustion.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(resilience):** clear persisted LKGP pins when a target suffers connection/provider exhaustion or is skipped before dispatch due to cooldown/exhaustion/unavailability, preventing subsequent requests from repeatedly prioritizing known-dead providers ([#11911](https://github.com/diegosouzapw/OmniRoute/issues/11911)).
|
||||
@@ -0,0 +1 @@
|
||||
- fix(ollama): preserve multi-byte UTF-8 content split across stream chunks in the Ollama NDJSON transform, which previously corrupted CJK/emoji into U+FFFD (#11921)
|
||||
1
changelog.d/fixes/11923-orcarouter-baseurl.md
Normal file
1
changelog.d/fixes/11923-orcarouter-baseurl.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(providers):** OrcaRouter chat requests now target `/v1/chat/completions` instead of the bare `/v1` API root, fixing the upstream `404 Invalid URL (POST /v1)` ([#11923](https://github.com/diegosouzapw/OmniRoute/pull/11923)).
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(plugins):** deliver the `onStreamComplete` event to disk-installed plugins. The event shipped in v3.8.50 (#9669) was emitted internally but had no plugin-facing wiring, so no plugin could ever subscribe: the manifest schema silently dropped `hooks.onStreamComplete`, and the loader/manager only knew the seven legacy hooks. `onStreamComplete` is now a declarable manifest hook, wired through the loader and registered by the manager like the other hooks, and its payload carries a `requestId` so consumers can correlate the stream-completion event with the originating request ([#11934](https://github.com/diegosouzapw/OmniRoute/pull/11934)) — thanks @amaleta
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(db):** the Qdrant embedding-model dropdown now lists local/self-hosted providers (Ollama, LM Studio, vLLM, etc.) — an active connection is treated as "configured" when the provider allows an optional API key, not only when it has a real key or OAuth, so a running local embedding provider is no longer hidden from the picker ([#11949](https://github.com/diegosouzapw/OmniRoute/issues/11949))
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(providers):** Vertex AI Anthropic partner-model discovery now calls the Model Garden `v1beta1` publisher list (`/v1beta1/publishers/anthropic/models`, global) and parses its `publisherModels` envelope, so Claude models auto-synced from Vertex populate the active live catalog and route at request time instead of returning `Model '<id>' is not available in the active live catalog` ([#11991](https://github.com/diegosouzapw/OmniRoute/issues/11991)) — thanks @fabioluissilva
|
||||
1
changelog.d/fixes/11999-cli-nodes-base-url-shadowing.md
Normal file
1
changelog.d/fixes/11999-cli-nodes-base-url-shadowing.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(cli):** support `--base-url` alongside `--endpoint` in `omniroute nodes add`, `update`, and `validate` subcommands to prevent global `--base-url` shadowing issues ([#11999](https://github.com/diegosouzapw/OmniRoute/issues/11999)).
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(providers):** `cloudflare-ai` no longer refuses image content parts for every Workers AI model ([#12002](https://github.com/diegosouzapw/OmniRoute/pull/12002)) — the plain-string `content` requirement behind #2539 is carried by the _model_ schema, not by the `/ai/v1/chat/completions` endpoint (measured: an all-text part array returns 200 on `@cf/mistralai/mistral-small-3.1-24b-instruct`, `@cf/meta/llama-4-scout-17b-16e-instruct` and `@cf/meta/llama-3.3-70b-instruct-fp8-fast`, and 400 on the text-only `@cf/qwen/qwen2.5-coder-32b-instruct`). `transformRequest()` flattened every array and threw on the first non-text part (#6390), so image input was refused for vision-capable Cloudflare models that accept it. All-text arrays are still flattened — the one shape every model accepts — while an array carrying a non-text part is passed through untouched, so the attachment is still never silently dropped. Regression guards: `tests/unit/cloudflare-ai-image-parts-6390.test.ts`.
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(resilience):** decouple the limiter-managed execution backstop from the queue-wait budget — new `requestQueue.executionMaxWaitMs` (env `RATE_LIMIT_EXECUTION_MAX_WAIT_MS`, default 600000 = 10 min) now feeds Bottleneck's post-dispatch `expiration`, while `requestQueue.maxWaitMs` keeps its documented queue-wait semantics. Previously the queue-wait budget doubled as the execution expiration, so legitimate long-running calls on non-incremental gateways (whole generation buffered before the first upstream byte, e.g. Console Go / Command Code tiers serving GLM models) were killed mid-flight at the queue budget with a false 504 `RATE_LIMIT_EXECUTION_TIMEOUT` — the local limiter undercut the provider-aware upstream fetch-start timeouts. The surfaced 504 message now names `requestQueue.executionMaxWaitMs`; the error keeps the #4165 guarantees (disclaims an upstream timeout, preserves the Bottleneck error as `cause`, branded code + trusted provenance, classified request-scoped so combo falls back). A real queue-wait bound (the `Promise.race` around `limiter.schedule()` sketched in #9533) remains future work. (#12025)
|
||||
@@ -0,0 +1 @@
|
||||
- **Call logs:** keep the `error` field when an artifact exceeds the storage cap, instead of replacing it with the omission marker. The error is the only field that says *why* a request failed and is typically ~90 bytes next to the multi-hundred-KB bodies that trip the cap, so dropping it left a size-limited row undiagnosable — a provider outage, a local timeout and an upstream 400 all rendered identically. It is now preserved at every fallback stage, truncated to 4KB if it is itself large ([#12026](https://github.com/diegosouzapw/OmniRoute/issues/12026)).
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(diagnostics):** preserve the error field (truncated to 4KB with a `[truncated: …]` suffix) in every call-log artifact size-limit fallback stage. Previously the minimal fallback replaced the error with `[omitted: call log artifact size limit exceeded]`, so an oversized artifact row showed nothing about WHY the request failed — e.g. 91 of 847 opencode-go 504 rows on one production instance were undiagnosable from the dashboard. Oversized request/response bodies are still omitted exactly as before; the error cap is independent of the payload sizes that tripped the fallback. (#12026)
|
||||
1
changelog.d/fixes/12031-web-search-call-emission.md
Normal file
1
changelog.d/fixes/12031-web-search-call-emission.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(sse):** OpenAI Responses clients that declare the native `web_search` tool now receive a spec-shaped `web_search_call` output item with `action.sources` alongside the preserved function-call round-trip, so search results executed through OmniRoute's own search backend are consumable by standard Responses clients (Codex, pi-web-access, …).
|
||||
1
changelog.d/fixes/12090-combo-explicit-context-length.md
Normal file
1
changelog.d/fixes/12090-combo-explicit-context-length.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(combo):** an operator-set **Agent Features → Context length** on a combo is now honored at request time. The value was persisted and advertised through `/v1/models`, but `resolveComboContextLimit()` never consulted it — so a multi-target combo whose members carry no per-model window fell through to the provider's generic `defaultContextLength` (openrouter 128000, command-code 200000) and rejected large requests with `Input exceeds context window … limit 128000` despite the combo being explicitly sized much larger. An identical single-target combo worked, because it collapses to its concrete target before the guard runs. Invalid values (0/negative/NaN/Infinity) are ignored, so the existing target → combo-min → fallback order is unchanged. ([#12090](https://github.com/diegosouzapw/OmniRoute/pull/12090)) — thanks @adivekar-utexas
|
||||
@@ -0,0 +1 @@
|
||||
- fix(sse): stop the auto-combo candidates inspector from silently dropping model-locked/cooled-down rows (#9133)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(executors):** handle DuckDuckGo ERR_BN_LIMIT (418) without retrying — when the upstream returns `418 ERR_BN_LIMIT` (rate-limit/ban), the executor now returns the error immediately instead of burning another VQD acquisition that would only count against the IP limit. The retry logic for `418 ERR_CHALLENGE` (unsolved challenge) remains unchanged. ([#11598](https://github.com/diegosouzapw/OmniRoute/pull/11598))
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(api):** Generated API CLI commands now enforce required OpenAPI request bodies; Combo test commands forward the required `comboName` body, while API keys created by older writers after migration 149 preserve legacy allow-all Combo access without widening explicit empty allowlists — thanks @marcelokarval
|
||||
@@ -0,0 +1 @@
|
||||
- Electron release: `electron/package-lock.json` regained the optional `electron-builder-squirrel-windows` subtree (13 entries) that `npm ci` had been refusing as out of sync, `electron-release.yml` gained a `build_ref` dispatch input and stops regenerating release notes on a re-attach dispatch, and the npm publish workflow attaches the SBOM to the GitHub Release on dispatch publishes too — so the v3.8.51 tag ships every desktop asset and the SBOM like v3.8.49 did
|
||||
@@ -0,0 +1 @@
|
||||
- **refactor(video bridge):** extract per-video acquisition, whole-result caching, description, and metrics/abort/cleanup out of `VideoBridgeGuardrail.preCall` into a `processVideoPart` seam in a new `videoBridgePipeline.ts`, behind explicit `VideoMediaBrokerPort`, `VideoAudioTranscriptionPort`, and `VideoDrilldownPort` boundaries; `preCall` now only handles request traversal, policy, and response aggregation. The Video tab's FFmpeg/ffprobe runtime status is now an explicit `unknown` / `restricted` / `unavailable` / `available` state instead of a nullable boolean pair, fixing a case where an in-flight or failed probe was mislabeled as "install FFmpeg" ([#11657](https://github.com/diegosouzapw/OmniRoute/issues/11657)).
|
||||
@@ -0,0 +1,5 @@
|
||||
- **docs(video):** clarify that the Video Bridge transcript `source` field (`client`,
|
||||
`embedded`, `audio-bridge`) is presently caller-declared and not yet server-verified —
|
||||
OmniRoute enforces the enum shape but does not cryptographically confirm that an
|
||||
`embedded`/`audio-bridge` label came from a server-owned extraction
|
||||
([#11661](https://github.com/diegosouzapw/OmniRoute/issues/11661)).
|
||||
1
changelog.d/maintenance/11753-wreq-js-transport.md
Normal file
1
changelog.d/maintenance/11753-wreq-js-transport.md
Normal file
@@ -0,0 +1 @@
|
||||
- **chore(stealth):** replace the `tls-client-node` sidecar/temp-file transport used by the six web-cookie providers with the exactly pinned `wreq-js` 3.0.0 native transport, preserving streaming, proxy isolation, deadlines, EOF policies, binary responses, and cancellation while removing the obsolete downloader and native repair path ([#11753](https://github.com/diegosouzapw/OmniRoute/pull/11753)).
|
||||
@@ -0,0 +1 @@
|
||||
- Stop painting every fork PR into `release/**` red: `quality.yml` `Build (advisory)` is skipped (GitHub still reports `continue-on-error` failures as check FAILURE). Hosted `ubuntu-latest` cannot finish `npm run build` on this tree — same class as #11962 taking `build.yml` off the PR rail. `docker-publish.yml` amd64 now runs on the `.113` `omni-build` pool (31 GB / 32 cores, two listeners) with Turbopack, shares the `heavy-build-main` lane with `ci.yml` `Build` so it queues instead of becoming a third heavy, and keeps per-ref concurrency (a merge storm was starting 8 concurrent OOM builds). arm64 stays on `ubuntu-24.04-arm` with webpack — there is no ARM box. Fallback when `USE_VPS_RUNNER` is off: hosted amd64 + webpack (#11976).
|
||||
@@ -0,0 +1 @@
|
||||
- `docker-publish.yml` builds with webpack (`OMNIROUTE_USE_TURBOPACK=0`) on **both** arches, including amd64 on the `.113` `omni-build` pool. Turbopack had the RAM (31 GB, `omniroute-113-6`) and still panicked (`TurbopackInternalError: there must be a path to a root`, run 33253576569, 26 min in). The same tree's arm64 webpack build on hosted `ubuntu-24.04-arm` succeeded (run 33264823398). Dockerfile already documents webpack as the Docker escape hatch (#11976).
|
||||
@@ -74,12 +74,6 @@
|
||||
"justification": "CC-BY-4.0 applies to the caniuse browser-support data (a dataset, not code). The Creative Commons Attribution license requires attribution when distributing — OmniRoute does not distribute caniuse-lite data directly to end users; it is consumed by browserslist/PostCSS at build time to generate CSS compatibility info. This is a widely accepted pattern in the Node.js ecosystem (caniuse-lite is in millions of projects). Attribution is satisfied by keeping the package in node_modules with its original license file.",
|
||||
"risk": "low",
|
||||
"reviewAt": "v4.0.0"
|
||||
},
|
||||
"tls-client-node": {
|
||||
"license": "Custom: LICENSE (Apache-2.0 + Commons Clause)",
|
||||
"justification": "TODO: revisar — tls-client-node uses Apache-2.0 with a 'Commons Clause' addendum that restricts 'Selling' the software (i.e., offering it as a hosted/commercial service whose value derives substantially from tls-client-node). OmniRoute is an open-source proxy; however if deployed as a paid SaaS/hosting service, this restriction could apply. The package is used by grokTlsClient.ts for Grok TLS fingerprinting. RISK: medium — legal review recommended before commercial deployment. Alternatives: consider replacing with a native TLS fingerprinting approach or a truly permissive library.",
|
||||
"risk": "medium",
|
||||
"reviewAt": "v3.9.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
401
config/quality/api-typecheck-baseline.json
Normal file
401
config/quality/api-typecheck-baseline.json
Normal file
@@ -0,0 +1,401 @@
|
||||
{
|
||||
"open-sse/transformer/responsesTransformer.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"open-sse/utils/progressTracker.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"open-sse/utils/sseHeartbeat.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"open-sse/utils/stream.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"src/app/api/assess/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/cache/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/cli-tools/all-statuses/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/cli-tools/claude-settings/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/cli-tools/cline-settings/route.ts": {
|
||||
"TS2339": 6
|
||||
},
|
||||
"src/app/api/cli-tools/codex-settings/route.ts": {
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/app/api/cli-tools/grok-build-settings/route.ts": {
|
||||
"TS2304": 2
|
||||
},
|
||||
"src/app/api/cli-tools/hermes-agent-settings/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/cli-tools/letta-settings/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/cli-tools/omp-settings/route.ts": {
|
||||
"TS2339": 10
|
||||
},
|
||||
"src/app/api/cli-tools/qwen-settings/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/combos/auto/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/combos/test/route.ts": {
|
||||
"TS2345": 2,
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/compression/compare/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/compression/preview/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/context/combos/[id]/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/context/combos/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/copilot/chat/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/guardrails/test/route.ts": {
|
||||
"TS2554": 2
|
||||
},
|
||||
"src/app/api/internal/codex-responses-ws/route.ts": {
|
||||
"TS2740": 2,
|
||||
"TS2339": 9
|
||||
},
|
||||
"src/app/api/keys/[id]/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/local/redis/start/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/local/redis/stop/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/logs/[id]/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/model-capability-overrides/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/model-combo-mappings/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/models/alias/route.ts": {
|
||||
"TS2339": 6
|
||||
},
|
||||
"src/app/api/models/route.ts": {
|
||||
"TS2345": 4,
|
||||
"TS2538": 2
|
||||
},
|
||||
"src/app/api/monitoring/health/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/oauth/codex/import-token/route.ts": {
|
||||
"TS2339": 4
|
||||
},
|
||||
"src/app/api/oauth/codex/import/route.ts": {
|
||||
"TS2554": 2,
|
||||
"TS2353": 2,
|
||||
"TS2339": 4
|
||||
},
|
||||
"src/app/api/oauth/cursor/login/poll/route.ts": {
|
||||
"TS2554": 2
|
||||
},
|
||||
"src/app/api/oauth/kiro/auto-import/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/omniroute/route/preview/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/playground/presets/[id]/route.ts": {
|
||||
"TS2339": 4
|
||||
},
|
||||
"src/app/api/provider-nodes/validate/route.ts": {
|
||||
"TS2339": 3
|
||||
},
|
||||
"src/app/api/providers/[id]/login/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/[id]/models/route.ts": {
|
||||
"TS2367": 2,
|
||||
"TS2339": 3,
|
||||
"TS2322": 3,
|
||||
"TS2554": 3,
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/app/api/providers/[id]/refresh-cursor/route.ts": {
|
||||
"TS2352": 2
|
||||
},
|
||||
"src/app/api/providers/[id]/refresh/route.ts": {
|
||||
"TS2345": 2,
|
||||
"TS2698": 2,
|
||||
"TS2339": 8
|
||||
},
|
||||
"src/app/api/providers/[id]/sync-models/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/providers/[id]/test/route.ts": {
|
||||
"TS2362": 2,
|
||||
"TS2698": 2
|
||||
},
|
||||
"src/app/api/providers/free-onboarding/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/providers/health-autopilot/actions/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/providers/route.ts": {
|
||||
"TS2352": 2,
|
||||
"TS2322": 3,
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/app/api/providers/test-batch/route.ts": {
|
||||
"TS2345": 5
|
||||
},
|
||||
"src/app/api/providers/validate/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/[sessionId]/cancel/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/[sessionId]/code/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/[sessionId]/identity/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/[sessionId]/resend/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/[sessionId]/status/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/providers/volcengine-plan/connect/route.ts": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/api/radar/local-model-state/route.ts": {
|
||||
"TS2339": 5
|
||||
},
|
||||
"src/app/api/resilience/model-cooldowns/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/services/_shared/installRoute.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/settings/cache-config/route.ts": {
|
||||
"TS2339": 2,
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/settings/database/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/settings/models-dev/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/settings/obsidian/webdav/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/settings/proxies/bulk-import/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/settings/proxy/cloudflare-deploy/route.ts": {
|
||||
"TS2769": 2,
|
||||
"TS2322": 3
|
||||
},
|
||||
"src/app/api/settings/proxy/deno-deploy/route.ts": {
|
||||
"TS2322": 5
|
||||
},
|
||||
"src/app/api/settings/proxy/vercel-deploy/route.ts": {
|
||||
"TS2322": 4
|
||||
},
|
||||
"src/app/api/settings/reasoning-routing-rules/[id]/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/settings/reasoning-routing-rules/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/settings/reasoning-routing-rules/simulate/route.ts": {
|
||||
"TS2322": 2,
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/system/env/repair/route.ts": {
|
||||
"TS2578": 2,
|
||||
"TS2353": 4
|
||||
},
|
||||
"src/app/api/system/version/route.ts": {
|
||||
"TS2769": 2
|
||||
},
|
||||
"src/app/api/tools/agent-bridge/agents/[id]/detected-models/route.ts": {
|
||||
"TS2769": 2
|
||||
},
|
||||
"src/app/api/tools/traffic-inspector/internal/ingest/route.ts": {
|
||||
"TS1117": 3,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/tools/traffic-inspector/ws/route.ts": {
|
||||
"TS2578": 2
|
||||
},
|
||||
"src/app/api/translator/send/route.ts": {
|
||||
"TS2345": 2,
|
||||
"TS2322": 2,
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/translator/translate/route.ts": {
|
||||
"TS2345": 2,
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/usage/analytics/route.ts": {
|
||||
"TS2352": 18
|
||||
},
|
||||
"src/app/api/usage/combo-health-autopilot/route.ts": {
|
||||
"TS2769": 3
|
||||
},
|
||||
"src/app/api/v1/batches/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/v1/classify/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/v1/files/[id]/content/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/v1/files/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/v1/images/edits/route.ts": {
|
||||
"TS2339": 22,
|
||||
"TS2322": 5
|
||||
},
|
||||
"src/app/api/v1/messages/count_tokens/route.ts": {
|
||||
"TS2339": 3,
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/v1/music/generations/route.ts": {
|
||||
"TS2322": 2,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/v1/ocr/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/v1/provider-plugin-manifest/route.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/v1/providers/[provider]/embeddings/route.ts": {
|
||||
"TS2339": 4,
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/v1/providers/[provider]/images/generations/route.ts": {
|
||||
"TS2339": 6
|
||||
},
|
||||
"src/app/api/v1/rerank/route.ts": {
|
||||
"TS2339": 3
|
||||
},
|
||||
"src/app/api/v1/segment/route.ts": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/api/v1/session-leases/route.ts": {
|
||||
"TS2339": 5,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/api/v1/speech-to-text/route.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"src/app/api/v1/text-to-speech/[voiceId]/route.ts": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"src/app/api/v1/web/fetch/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/v1beta/models/route.ts": {
|
||||
"TS2345": 2,
|
||||
"TS2538": 2
|
||||
},
|
||||
"src/app/api/version-manager/restart/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/version-manager/start/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/version-manager/stop/route.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/api/webhooks/[id]/route.ts": {
|
||||
"TS2554": 2
|
||||
},
|
||||
"src/app/api/webhooks/[id]/test/route.ts": {
|
||||
"TS2352": 3
|
||||
},
|
||||
"src/app/api/webhooks/route.ts": {
|
||||
"TS2554": 2,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/lib/db/tierConfig.ts": {
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/lib/monitoring/comboHealthAutopilot.ts": {
|
||||
"TS2305": 2,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/lib/monitoring/providerHealthAutopilot.ts": {
|
||||
"TS2352": 5
|
||||
},
|
||||
"src/lib/omnirouteStatus.ts": {
|
||||
"TS2322": 2,
|
||||
"TS2558": 2
|
||||
},
|
||||
"src/lib/providerModels/managedModelImport.ts": {
|
||||
"TS2352": 5
|
||||
},
|
||||
"src/lib/proxySubscription/parse.ts": {
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/lib/quota/quotaAnalytics.ts": {
|
||||
"TS2769": 2
|
||||
},
|
||||
"src/lib/quota/quotaResetTimers.ts": {
|
||||
"TS2769": 3
|
||||
},
|
||||
"src/lib/usage/comboForecast.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/lib/usage/comboHealth.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/lib/usage/comboScoringInspector.ts": {
|
||||
"TS2352": 2,
|
||||
"TS2741": 2
|
||||
},
|
||||
"src/lib/usage/providerWindowCosts.ts": {
|
||||
"TS2322": 3,
|
||||
"TS2558": 6,
|
||||
"TS2339": 15,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/lib/vscode/modelPresentation.ts": {
|
||||
"TS2554": 2
|
||||
},
|
||||
"src/lib/ws/handshake.ts": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/mitm/detection/index.ts": {
|
||||
"TS2741": 2
|
||||
},
|
||||
"src/mitm/inspector/httpProxyServer.ts": {
|
||||
"TS2769": 2
|
||||
},
|
||||
"src/shared/schemas/cliCatalog.ts": {
|
||||
"TS2554": 3
|
||||
},
|
||||
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (289 → 455); velocity phase, see quality-baseline.json _policy."
|
||||
}
|
||||
@@ -1,54 +1,54 @@
|
||||
{
|
||||
"_comment": "Catraca de complexidade (check-complexity.mjs, ESLint core rules complexity>=15 e max-lines-per-function>80 sobre src+open-sse+electron+bin via eslint.complexity.config.mjs). Conta total de violacoes; so pode cair. --update ratcheta.",
|
||||
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "2130->2175. PR #8523 (Dario embedded service, upstream-proxy mode selector): check:complexity does not run on PR->release fast-gates, so cycle drift accrues unratcheted until a PR trips the gate (same pattern as every _rebaseline_ entry above). Measured base upstream/release/v3.8.49 tip locally at 2169 (with this PR\u0027s own commits removed); this branch measures 2173 local, 2175 on the CI runner (same local-vs-CI off-by-few convention documented in _rebaseline_2026_07_02_v3844_ci_observed). This PR\u0027s own genuine contribution is small (+4 to +6): the new mode <select> branching in ConnectionRow.tsx (Native/CLIProxyAPI/Dario/Fallback + conditional fallback-backend picker) and the probe/adopt/kill-PID branches added to the service supervisor for Dario\u0027s on-demand lifecycle. Using the CI-observed value (2175) so the gate is deterministic where it actually runs, per the established convention. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "2130->2175. PR #8523 (Dario embedded service, upstream-proxy mode selector): check:complexity does not run on PR->release fast-gates, so cycle drift accrues unratcheted until a PR trips the gate (same pattern as every _rebaseline_ entry above). Measured base upstream/release/v3.8.49 tip locally at 2169 (with this PR's own commits removed); this branch measures 2173 local, 2175 on the CI runner (same local-vs-CI off-by-few convention documented in _rebaseline_2026_07_02_v3844_ci_observed). This PR's own genuine contribution is small (+4 to +6): the new mode <select> branching in ConnectionRow.tsx (Native/CLIProxyAPI/Dario/Fallback + conditional fallback-backend picker) and the probe/adopt/kill-PID branches added to the service supervisor for Dario's on-demand lifecycle. Using the CI-observed value (2175) so the gate is deterministic where it actually runs, per the established convention. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_20_owner_night_drain": "Owner-approved (chat, 2026-07-20 ~00:50): 2072->2130. The day's 17 merged PRs consumed the entire slack (tip at 2069/2072); queue PRs #6973(+4)/#7662(+2)/#7719(+1) plus the #7744/#7779 reworks were collectively blocked. Owner chose a wide margin for the remainder of the v3.8.49 cycle instead of per-PR extraction.",
|
||||
"count": 2175,
|
||||
"count": 3218,
|
||||
"_rebaseline_2026_07_25_8470_hyperagent_sticky_thread": "2130->2170 (+40). PR #8470 (artickc, fix/hyperagent-tool-loop-thread-sticky) pre-green validation. Trust-but-verify: origin/release/v3.8.49 tip alone (pristine, no PR changes) already measures 2169 with node scripts/check/check-complexity.mjs — i.e. +39 is inherited cycle drift unrelated to this PR (the cyclomatic-complexity ratchet does not run on PR->release fast-gates). This PR's OWN growth adds exactly +1: per-file eslint scoped scan on open-sse/executors/hyperagent.ts (base vs PR) shows extractMessageText() crossing the complexity>=15 threshold for the first time (new violation, complexity 25) from the new Anthropic tool_use/tool_result flattening branches; resolveHyperAgentThreadBinding's existing pre-#8470 violation (18) grows to 25 (still counted once, from the new root-key lookup tier); createHyperAgentThread and execute() are unchanged pre-existing violations. Net repo-wide total = 2169 (inherited drift) + 1 (this PR's own new violation) = 2170. Full-repo re-measurement of the merged branch was attempted but not completed live due to heavy concurrent devbox load (many other /green-prs sessions running the identical full-repo eslint scan in parallel); derived from two independently-clean measurements (base-tip full scan + per-file base-vs-PR delta). Covered by tests/unit/executor-hyperagent.test.ts (19/19). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 2169->2183 (+14). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 2183 on the combined boarded tree (tip ac15014ca7) vs 2169 on the pristine release tip. Each boarded PR sits under the ceiling individually, but the combined batch adds +14 (new branches in #8378 chatCore contextLimit / #8432 cursor native_todo / #8476 combo input-bound / #8526 combo select-all modals / etc \u2014 the pre-screen-flagged complexity-growth set). Same merge-burst-inherited-drift class as the notes below; owner chose absorbing the ceiling over per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25_v3849_mergequeue_drain": "Owner-approved (chat, 2026-07-25): 2130->2169 (+39). v3.8.49 /merge-prs queue-drain: the cycle's merge burst (the 8 base-red slices + owner PRs + parallel-session merges #8500-8508) accrued inherited cyclomatic drift the fast-path PR->release never ratchets (check:complexity does not run on PR->release). Measured 2169 on the pristine release tip 4053e2314a alone (BEFORE any queue PR boards) \u2014 so the entire +39 is base drift already on the tip, not any queued PR's own growth. Every merge-ready PR in the queue was tripping Fast Quality Gates on this shared base-red. Owner approved raising the ceiling to the measured tip value so the ~34-PR merge-train lands without per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct: 2188->2774 (+586, +26.8% over pristine 2188). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +124 (2x daily drift) on 2026-07-27; v2 = v1 +20% buffer = +218 \u2192 +586 total (cycle 2188 measured pristine \u2192 2774 ceiling). Justification: v3.8.50 release cut coincides with high-merge activity (33-PR Train 1D + ~37-PR Train 2 backlog + post-freeze re-home rebase churn); owner accepted enlarging the headroom so the entire PREPARE phase window (5 minor cycles: .50-.54) flows without per-PR rebaseline noise, given that re-tightening happens mechanically at v3.8.51 via #8675/#8700 decomposition work scheduled in .51 (Executor registry in-place + combo.ts decomposition per ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 492 from structural extraction during #8675/#8700 decomposition campaigns + combo.ts split scheduled in .52, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 2282 floor still gives 94 units of post-tighten headroom vs the current pristine 2188. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut, 2026-07-28 target) \u2192 v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md). This entry is the LAST rebaseline in this file unless a measured regression appears. v1 entry retained below for audit trail.",
|
||||
"count": 2774,
|
||||
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten: 2188->2312 (+124). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +124 = 2x the daily drift observed in jul (~4.5 cyclomatic/day over 25d = ~114); covers ~28d of normal merge activity without per-PR rebaseline churn. RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 30 from structural extraction during #8675/#8700 decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears). Tracked via roadmap issue (TO BE OPENED). Window: 3.8.50 (release cut) \u2192 3.8.54 close (re-tighten at 3.8.51 prep merge per ROADMAP.md). SUPERSEDED by _rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct (v1 +20% buffer) \u2014 retained for audit. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut) \u2192 v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md).",
|
||||
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 2169->2183 (+14). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 2183 on the combined boarded tree (tip ac15014ca7) vs 2169 on the pristine release tip. Each boarded PR sits under the ceiling individually, but the combined batch adds +14 (new branches in #8378 chatCore contextLimit / #8432 cursor native_todo / #8476 combo input-bound / #8526 combo select-all modals / etc — the pre-screen-flagged complexity-growth set). Same merge-burst-inherited-drift class as the notes below; owner chose absorbing the ceiling over per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25_v3849_mergequeue_drain": "Owner-approved (chat, 2026-07-25): 2130->2169 (+39). v3.8.49 /merge-prs queue-drain: the cycle's merge burst (the 8 base-red slices + owner PRs + parallel-session merges #8500-8508) accrued inherited cyclomatic drift the fast-path PR->release never ratchets (check:complexity does not run on PR->release). Measured 2169 on the pristine release tip 4053e2314a alone (BEFORE any queue PR boards) — so the entire +39 is base drift already on the tip, not any queued PR's own growth. Every merge-ready PR in the queue was tripping Fast Quality Gates on this shared base-red. Owner approved raising the ceiling to the measured tip value so the ~34-PR merge-train lands without per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct: 2188->2774 (+586, +26.8% over pristine 2188). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +124 (2x daily drift) on 2026-07-27; v2 = v1 +20% buffer = +218 → +586 total (cycle 2188 measured pristine → 2774 ceiling). Justification: v3.8.50 release cut coincides with high-merge activity (33-PR Train 1D + ~37-PR Train 2 backlog + post-freeze re-home rebase churn); owner accepted enlarging the headroom so the entire PREPARE phase window (5 minor cycles: .50-.54) flows without per-PR rebaseline noise, given that re-tightening happens mechanically at v3.8.51 via #8675/#8700 decomposition work scheduled in .51 (Executor registry in-place + combo.ts decomposition per ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 492 from structural extraction during #8675/#8700 decomposition campaigns + combo.ts split scheduled in .52, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 2282 floor still gives 94 units of post-tighten headroom vs the current pristine 2188. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut, 2026-07-28 target) → v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md). This entry is the LAST rebaseline in this file unless a measured regression appears. v1 entry retained below for audit trail.",
|
||||
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten: 2188->2312 (+124). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +124 = 2x the daily drift observed in jul (~4.5 cyclomatic/day over 25d = ~114); covers ~28d of normal merge activity without per-PR rebaseline churn. RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 30 from structural extraction during #8675/#8700 decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears). Tracked via roadmap issue (TO BE OPENED). Window: 3.8.50 (release cut) → 3.8.54 close (re-tighten at 3.8.51 prep merge per ROADMAP.md). SUPERSEDED by _rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct (v1 +20% buffer) — retained for audit. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut) → v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md).",
|
||||
"_rebaseline_2026_07_19_v3849_fix_sweep_cluster": "2059->2072 (owner-approved, 2026-07-19). /fix-prs validation-train sweep: a cluster of otherwise-clean contributor PRs (#6973/#7683/#7662/#7672/#7633/#7767, each +1/+2 cyclomatic own-growth from new provider/auth/combo branches) collectively pushed the count from tip 2056 to 2068. Individually all but #6973 sit under the old 2059 baseline; combined they exceed it. The tip had only 3 units of slack (2056 vs 2059), so every new-feature PR was tripping the ratchet (this was the 4th such block of the day after #7695/#7747/#7768). Owner approved raising the ceiling to 2072 = combined-cluster 2068 + 4 units headroom, so the cluster lands without per-PR helper-extraction churn and near-term feature PRs have breathing room. Measured 2068 on the 9-PR combined probe tree. Structural shrink stays debt (#3501); tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_18_pr7360_quota_visibility_resync": "2058->2059 (+1 vs recorded ceiling; measured 2056 fresh on release tip cab9e5f0c alone, so this ceiling still carries 2 units of un-banked slack from prior shrinkage \u2014 real regression from this merge is 2056->2059, +3). PR #7360 (JxnLexn) release-resync: merging origin/release/v3.8.49 to resolve the 3-file conflict (ConnectionRow.tsx/ConnectionsListPanel.tsx/useProviderConnections.ts) unions two already-compliant features in the same already-oversized god-component: release's confirm-delete-account wiring (#7361) and this PR's per-connection quota-visibility wiring. Diffed release-tip-only vs merged violation lists (scripts dumped via getComplexityEslintReport): most entries are the SAME pre-existing violations shifted a few lines (ConnectionRow/getStatusPresentation/inferErrorType \u2014 no count change) or marginally bigger (ConnectionRow function complexity 85->86, ConnectionsListPanel function 498->510 lines) from the two ConnectionRow call sites each gaining both PRs' multi-line JSX props. The 2 genuinely NEW crossings are the 'no tag' and 'tagged groups' .map() render callbacks in ConnectionsListPanel.tsx (83 and 85 lines, was <=80 on both parents individually) tipping over 80 lines specifically because both PRs' props land on the same call sites. No new logic was written during the resync itself (only import-statement unions); the growth is inherent to combining the two already-reviewed feature branches. Structural shrink tracked in #3501. Tighten via --update next cycle (true floor is 2056, not 2058).",
|
||||
"_rebaseline_2026_07_18_pr7360_quota_visibility_resync": "2058->2059 (+1 vs recorded ceiling; measured 2056 fresh on release tip cab9e5f0c alone, so this ceiling still carries 2 units of un-banked slack from prior shrinkage — real regression from this merge is 2056->2059, +3). PR #7360 (JxnLexn) release-resync: merging origin/release/v3.8.49 to resolve the 3-file conflict (ConnectionRow.tsx/ConnectionsListPanel.tsx/useProviderConnections.ts) unions two already-compliant features in the same already-oversized god-component: release's confirm-delete-account wiring (#7361) and this PR's per-connection quota-visibility wiring. Diffed release-tip-only vs merged violation lists (scripts dumped via getComplexityEslintReport): most entries are the SAME pre-existing violations shifted a few lines (ConnectionRow/getStatusPresentation/inferErrorType — no count change) or marginally bigger (ConnectionRow function complexity 85->86, ConnectionsListPanel function 498->510 lines) from the two ConnectionRow call sites each gaining both PRs' multi-line JSX props. The 2 genuinely NEW crossings are the 'no tag' and 'tagged groups' .map() render callbacks in ConnectionsListPanel.tsx (83 and 85 lines, was <=80 on both parents individually) tipping over 80 lines specifically because both PRs' props land on the same call sites. No new logic was written during the resync itself (only import-statement unions); the growth is inherent to combining the two already-reviewed feature branches. Structural shrink tracked in #3501. Tighten via --update next cycle (true floor is 2056, not 2058).",
|
||||
"_rebaseline_2026_07_17_v3849_ownerprs_providers": "2056->2058 (+2). v3.8.49 owner-PR merge campaign own-growth: the new provider handlers/dispatch branches merged this cycle (freetheai/felo/notion/segmind/deepinfra/novita/msdesigner image+video handlers, each adding a format-dispatch guard) pushed cyclomatic violations 2056->2058. Fast-gates PR->release do not run the complexity ratchet, so this surfaced only on re-sync. Spread across the new leaf handlers (not a single extractable function); measured on the release tip. Structural shrink tracked in #3501.",
|
||||
"_rebaseline_2026_07_10_v3847_merge_burst": "2053->2054 (+1). Drift herdado do merge burst do dia em release/v3.8.47 (campanha /implement-prs: ~36 PRs mergeados \u2014 \u00f3rf\u00e3os, features do dono, ports). O check:complexity N\u00c3O roda no fast-path PR->release, ent\u00e3o o ramo acumulou o +1 sem rebaselinar (mesma fam\u00edlia de todos os rebaselines abaixo). Trust-but-verify: medido 2054 no tip da release p\u00f3s-burst; a \u00fanica fun\u00e7\u00e3o flagada nova \u00e9 pr\u00e9-existente (getResolvedModelCapabilities em modelCapabilities.ts, j\u00e1 >teto antes de #6714). Nenhum PR \u00f3rf\u00e3o/feature introduz viola\u00e7\u00e3o NOVA \u2014 os fixes deste ciclo s\u00e3o complexity-net-zero. Rebaseline aprovado pelo dono (2026-07-10) para destravar o FQG dos ~7 \u00f3rf\u00e3os verdes-exceto-complexity. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_10_v3847_merge_burst": "2053->2054 (+1). Drift herdado do merge burst do dia em release/v3.8.47 (campanha /implement-prs: ~36 PRs mergeados — órfãos, features do dono, ports). O check:complexity NÃO roda no fast-path PR->release, então o ramo acumulou o +1 sem rebaselinar (mesma família de todos os rebaselines abaixo). Trust-but-verify: medido 2054 no tip da release pós-burst; a única função flagada nova é pré-existente (getResolvedModelCapabilities em modelCapabilities.ts, já >teto antes de #6714). Nenhum PR órfão/feature introduz violação NOVA — os fixes deste ciclo são complexity-net-zero. Rebaseline aprovado pelo dono (2026-07-10) para destravar o FQG dos ~7 órfãos verdes-exceto-complexity. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_10_gcf_v3_2": "2054->2056 (+2). PR feat/headroom-gcf-v3.2-nested-flattening: own growth from re-vendoring the GCF (Headroom) codec to spec v3.2 (nested flattening). The 2 new over-threshold functions are the v3.2 `>`-path flatten/unflatten walk in the vendored generic-profile encode/decode paths (open-sse/services/compression/engines/headroom/gcf/{generic,decode_generic}.ts). This is imported third-party code kept byte-faithful to upstream gcf-typescript, not extractable without diverging from the vendored source; local measures 2055 on the merged tree; frozen at 2056 = the base's CI-observed 2054 + this PR's 2 new functions, matching the documented local-vs-CI off-by-one convention (see _rebaseline_2026_07_02_v3844_ci_observed) so the GitHub runner stays green. Round-trip guarded by tests/unit/compression/headroom-smartcrusher.test.ts (deep-nested case). Structural shrink belongs upstream in gcf, not here.",
|
||||
"_rebaseline_2026_07_08_6556_inherited_drift": "2052->2053 (+1). PR #6556 (omniglyph engine): drift herdado do merge burst da base (a catraca nao roda no fast-path PR->release, mesmo padrao dos rebaselines v3.8.44/46). Trust-but-verify: o proprio codigo do PR e complexity-net-zero \u2014 as 2 violacoes que ele introduzia (runCompressionAsync complexity 17 apos o branch do modo omniglyph; OmniglyphContextPageClient 161 linhas) foram CORRIGIDAS por extracao real (engines/omniglyphSingleMode.ts + split do componente em section components), medido: 2055->2053 local; base pura origin/release/v3.8.47 mede 2053 identico. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_07_v3846_release_close": "2035->2050 (+15). v3.8.46 release close (generate-release Phase 0 pre-flight): drift herdado do merge burst do ciclo (39 commits do dia + campanha /review-*). Trust-but-verify: os fixes de base-red do captain (agentSkills path.resolve #6366, catalogo cache #6408, tipagem de teste no-explicit-any, MitmProxyTab suppression) sao complexity-net-zero \u2014 check:complexity mede 2050 identico com e sem os fixes (a catraca NAO roda no fast-path PR->release, entao o ramo acumulou sem rebaselinar). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_04_v3844_release_close": "2026->2028 (+2). v3.8.44 release close (generate-release Phase 0/1): drift residual do fim do ciclo medido no tip pos-#6155 (merge burst final: #6155 cooling-panel + #6104 Kenari + #6139/#6128 provider-limits). Trust-but-verify: os 2 fixes de codigo do release-captain (model.ts alias boundary, auggie.ts stdin error handlers) adicionam 0 violacoes NOVAS \u2014 eslint.complexity direto nos 2 arquivos flagra apenas funcoes que ja estouravam o limite antes (runStreaming/start ja >80 linhas; resolveModelByProviderInference/getModelInfoCore pre-existentes de #5918), e resolveProviderAlias segue abaixo de 15. Logo o +2 e drift herdado do burst. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_08_6556_inherited_drift": "2052->2053 (+1). PR #6556 (omniglyph engine): drift herdado do merge burst da base (a catraca nao roda no fast-path PR->release, mesmo padrao dos rebaselines v3.8.44/46). Trust-but-verify: o proprio codigo do PR e complexity-net-zero — as 2 violacoes que ele introduzia (runCompressionAsync complexity 17 apos o branch do modo omniglyph; OmniglyphContextPageClient 161 linhas) foram CORRIGIDAS por extracao real (engines/omniglyphSingleMode.ts + split do componente em section components), medido: 2055->2053 local; base pura origin/release/v3.8.47 mede 2053 identico. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_07_v3846_release_close": "2035->2050 (+15). v3.8.46 release close (generate-release Phase 0 pre-flight): drift herdado do merge burst do ciclo (39 commits do dia + campanha /review-*). Trust-but-verify: os fixes de base-red do captain (agentSkills path.resolve #6366, catalogo cache #6408, tipagem de teste no-explicit-any, MitmProxyTab suppression) sao complexity-net-zero — check:complexity mede 2050 identico com e sem os fixes (a catraca NAO roda no fast-path PR->release, entao o ramo acumulou sem rebaselinar). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_04_v3844_release_close": "2026->2028 (+2). v3.8.44 release close (generate-release Phase 0/1): drift residual do fim do ciclo medido no tip pos-#6155 (merge burst final: #6155 cooling-panel + #6104 Kenari + #6139/#6128 provider-limits). Trust-but-verify: os 2 fixes de codigo do release-captain (model.ts alias boundary, auggie.ts stdin error handlers) adicionam 0 violacoes NOVAS — eslint.complexity direto nos 2 arquivos flagra apenas funcoes que ja estouravam o limite antes (runStreaming/start ja >80 linhas; resolveModelByProviderInference/getModelInfoCore pre-existentes de #5918), e resolveProviderAlias segue abaixo de 15. Logo o +2 e drift herdado do burst. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_03_v3844_ipfilter_release_green": "2015->2026 (+11). v3.8.44 cycle drift measured on release tip 32e4c906e during the #6131/#5975 release-green rebaseline. Inherited from the merge burst (Quality Ratchet does not run on PR->release fast-gates). route-edge-coverage +7 is my #5975 test comment; the rest is parallel-session drift. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_03_6007_sidecar_manifest": "2007->2015. PR #6007 (re-cut) adds sidecar/provider-manifest header wiring and the public manifest URL helper; the feature files themselves introduce 0 new complexity violations (check-complexity flags none in providerPluginManifestUrl.ts). The +8 vs the 2007 release baseline is inherited release/v3.8.44 drift absorbed at merge (check:complexity measures 2015 on the current release tip). Tighten via --update next cycle / at /generate-release Phase 0.",
|
||||
"_rebaseline_2026_07_02_v3844_ci_observed": "2006->2007 (+1). Local Ubuntu measures 2006 on this tree; the GitHub fast-gates runner measures 2007 (same local-vs-CI off-by-one already documented in _rebaseline_2026_06_26_v3838_release_fast_gate). Use the CI-observed value so the gate is deterministic where it actually runs.",
|
||||
"_rebaseline_2026_07_02_v3844_post_5939": "2003->2006 (+3). Inherited drift from the release/v3.8.44 merges after 3a3d618fe (#5809 audio translations et al.), surfaced by PR fix#5959: check:complexity measures 2006 on the pristine base (cbd08ef78) WITH AND WITHOUT this PR's one-line CLI change (verified by reverting the file and re-measuring) \u2014 the PR is complexity-net-zero. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_02_v3844_merge_burst": "1995->2003 (+8). Inherited v3.8.44 cycle drift surfaced by PR #5939: check:complexity measures 2003 on BOTH the pristine release tip (3a3d618fe) and this PR's merged HEAD \u2014 identical, so all +8 came from the 2026-07-02 merge burst into release/v3.8.44 (#5933 codex schema, #5950 OCR, #5904/#5920 combo, #6000/#6008 executor refactors, etc.) merged while the fast-gates queue was base-red (file-size #5933). PR #5939 itself was verified complexity-net-zero during its own CI cycle (DiscoveryPageClient refactored into hooks/sub-components to stay under max-lines-per-function). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_02_5798_release_green": "1982->1995 (+13). Inherited v3.8.43 cycle drift surfaced by the release-green unblock #5798 / PR #5896: check:complexity measures 1995 on BOTH the pristine release tip (0d3875a98) and this PR's HEAD \u2014 identical, so all +13 came from the 2026-07-01/02 merge burst (providers/usage/dashboard fixes merged via --admin while the fast-gates queue was base-red). This PR touches only gate scripts, docs, baselines and test files \u2014 0 production logic. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_01_v3843_release": "1981->1982 (+1). v3.8.43 cycle drift, surfaced after check:mutation-test-coverage was fixed (it was masked behind that earlier step in the Fast Quality Gates chain). 1982 = the value measured by check:complexity on BOTH fce85136c (release tip) and 6d7060e21 (release + the 5 CI fixes) \u2014 identical, so all +1 is inherited cycle drift; the fixes touch only test files + linkify.ts safeHttpHref (cyclomatic ~4, well under the >=15 threshold, 0 new violations) + config JSON. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_06_28_v3840_5237_reconcile": "1980->1981 (+1). Inherited release/v3.8.40 drift surfaced while merging PR #5237 (impersonation-UA refresh) \u2014 the +1 is present on the pristine release tip (d8a392a47) WITHOUT #5237's changes, so it is #5222 (antigravity fallback-LRU retry) / #5221 (command-code) growth that merged via --admin without ratcheting complexity (the PR->release fast-gates do not run check:complexity). #5237 itself is complexity-net-zero: its only edits are a single UA constant, a regenerated golden snapshot, and baseline JSONs. Structural reduction tracked in #3501.",
|
||||
"_rebaseline_2026_06_27_v3838_release": "1978->1980 (+2). v3.8.38 cycle-close drift surfaced by the release-green pre-flight (check:complexity does NOT run on PR->release fast-gates). +2 from late-cycle feature/fix merges (compression fidelity-gate steps #5143, SSE hardening). Release-finalize working tree touches ONLY CHANGELOG.md + i18n mirrors + the 2 baseline JSONs \u2014 0 production-code change. Structural reduction tracked in #3501.",
|
||||
"_rebaseline_2026_07_02_v3844_post_5939": "2003->2006 (+3). Inherited drift from the release/v3.8.44 merges after 3a3d618fe (#5809 audio translations et al.), surfaced by PR fix#5959: check:complexity measures 2006 on the pristine base (cbd08ef78) WITH AND WITHOUT this PR's one-line CLI change (verified by reverting the file and re-measuring) — the PR is complexity-net-zero. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_02_v3844_merge_burst": "1995->2003 (+8). Inherited v3.8.44 cycle drift surfaced by PR #5939: check:complexity measures 2003 on BOTH the pristine release tip (3a3d618fe) and this PR's merged HEAD — identical, so all +8 came from the 2026-07-02 merge burst into release/v3.8.44 (#5933 codex schema, #5950 OCR, #5904/#5920 combo, #6000/#6008 executor refactors, etc.) merged while the fast-gates queue was base-red (file-size #5933). PR #5939 itself was verified complexity-net-zero during its own CI cycle (DiscoveryPageClient refactored into hooks/sub-components to stay under max-lines-per-function). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_02_5798_release_green": "1982->1995 (+13). Inherited v3.8.43 cycle drift surfaced by the release-green unblock #5798 / PR #5896: check:complexity measures 1995 on BOTH the pristine release tip (0d3875a98) and this PR's HEAD — identical, so all +13 came from the 2026-07-01/02 merge burst (providers/usage/dashboard fixes merged via --admin while the fast-gates queue was base-red). This PR touches only gate scripts, docs, baselines and test files — 0 production logic. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_01_v3843_release": "1981->1982 (+1). v3.8.43 cycle drift, surfaced after check:mutation-test-coverage was fixed (it was masked behind that earlier step in the Fast Quality Gates chain). 1982 = the value measured by check:complexity on BOTH fce85136c (release tip) and 6d7060e21 (release + the 5 CI fixes) — identical, so all +1 is inherited cycle drift; the fixes touch only test files + linkify.ts safeHttpHref (cyclomatic ~4, well under the >=15 threshold, 0 new violations) + config JSON. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_06_28_v3840_5237_reconcile": "1980->1981 (+1). Inherited release/v3.8.40 drift surfaced while merging PR #5237 (impersonation-UA refresh) — the +1 is present on the pristine release tip (d8a392a47) WITHOUT #5237's changes, so it is #5222 (antigravity fallback-LRU retry) / #5221 (command-code) growth that merged via --admin without ratcheting complexity (the PR->release fast-gates do not run check:complexity). #5237 itself is complexity-net-zero: its only edits are a single UA constant, a regenerated golden snapshot, and baseline JSONs. Structural reduction tracked in #3501.",
|
||||
"_rebaseline_2026_06_27_v3838_release": "1978->1980 (+2). v3.8.38 cycle-close drift surfaced by the release-green pre-flight (check:complexity does NOT run on PR->release fast-gates). +2 from late-cycle feature/fix merges (compression fidelity-gate steps #5143, SSE hardening). Release-finalize working tree touches ONLY CHANGELOG.md + i18n mirrors + the 2 baseline JSONs — 0 production-code change. Structural reduction tracked in #3501.",
|
||||
"_rebaseline_2026_06_26_v3838_ownerprs_batch": "1972->1978 (+6). Drift do lote de merges de PRs do dono + contribuidores em release/v3.8.38 (sessao /review-prs): #4845 (antigravity convertGeminiToOpenAI), #5105 (executor zenmux-free), #5020 (executor grok-cli), #4940 (usage dedupe guard), #5093 (resilience: quota cutoff/gemini mime/model-lockout cooldown), #5015 (quota hydration + auto-combo scoping). Cada um e crescimento de feature/fix legitimo recem-TDD'd, nao regressao; o gate check:complexity NAO roda no fast-path PR->release, entao o ramo acumula sem rebaselinar (mesma familia dos rebaselines anteriores). #5121 cookie-dedup foi mantido complexity-NEUTRO via extracao do helper findExistingCookieConnection. Reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_26_v3838_release_fast_gate": "1963->1972 (+9). Reconciles inherited release/v3.8.38 drift surfaced by PR #5124. Local origin/release/v3.8.38 measured 1971 and this PR also measured 1971 after refactoring the new JSON-body SSE sniffing path, while the GitHub Ubuntu fast gate measured 1972; use the CI-observed value so the release branch gate is deterministic. The streaming fix is complexity-net-zero relative to the local release base. The release fast-path does not consistently ratchet complexity between release-cycle merges; keep structural reductions as separate debt.",
|
||||
"_rebaseline_2026_06_25_v3836_release": "Reconciliacao release-volatil 1920->1950 (+30) no fechamento do ciclo v3.8.36, surfada pelo CI da fix-PR #5029 (a catraca de complexidade NAO roda no fast-path PR->release nem foi medida no release PR #4854 \u2014 Quality Ratchet foi SKIPPED la \u2014 so PR->main, entao o ramo acumulou os 137 commits sem rebaselinar). O +30 e drift de condicionais NOVOS das features legitimas do ciclo: Quota-Share Fase 2/3 (estrategia dedicada DRR+P2C, multi-window buckets, concurrency control, headroom, saturacao proativa \u2014 #4885/#4907/#4908/#4927/#4928/#4929/#4939/#4965/#4967/#4970), task-aware + Fusion combo (#4945/#4652), e ramos de provider/translator de contribuidores. A god-file decomposition #3501 e PURA (move codigo p/ leaves, complexity-neutra). Verificado que esta fix-PR (#5029) toca SO scripts/build/pack-artifact-policy.ts (array de strings), tests/integration/resilience-http-e2e.test.ts (2 keys) e os 2 baselines json \u2014 contribui 0 ao gate que varre src+open-sse+electron+bin. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_23_v3835_release": "Reconciliacao release-volatil 1916->1920 (+4) no fechamento do ciclo v3.8.35, surfada pelo pre-flight check:release-green (a catraca de complexidade NAO roda no fast-path PR->release, so release->main, entao o ramo acumula sem rebaselinar). O +4 e drift de condicionais NOVOS dos merges de contribuidor/feature deste ciclo (Compression Phase 4 #4694/#4707/#4716/#4720, combos auto-promote #4774, tier no-auth #4753, deepseek-web tool-fold #4756, dedupe provider nodes #4768). Verificado que o trabalho de release-finalize desta sessao toca SO docs/*.md (THREAT_MODEL), CHANGELOG.md, baselines e 1 linha de string em scripts/check/check-fabricated-docs.mjs (fora do escopo src+open-sse+electron+bin que o gate varre) \u2014 contribui 0. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_23_v3834_release": "Reconciliacao release-volatil 1915->1916 (+1) no fechamento do ciclo v3.8.34. check:complexity NAO roda no fast-path PR->release (so release->main), entao o ramo acumula sem rebaselinar; surfou no full CI do release PR (run em c98e7ff6d). O +1 e drift de condicional NOVO de merge de contribuidor do ciclo (features quota/usage/opencode-go/M365). Verificado que o commit de release-finalize NAO adiciona complexity: toca CHANGELOG/baseline/mirrors/3 testes + 1 linha de regex em opencodeOllamaUsage.ts (sem novo ramo) + reorder de dados no reka registry \u2014 local mede 1916 com ou sem essa mudanca. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_4537_nested_combo": "Reconciliacao 1913->1915 (+2) do PR #4537 (nestedComboMode execute \u2014 black-box combo-ref execution). O +2 vem do branch novo de dispatch nested em handleComboChat (combo.ts: normalizeNestedComboMode + executeModeUnits/hasExecutableComboRef + o ramo simpleExecuteStrategies que roda resolveComboRuntimeUnits com recursion caps depth/cycle/budget) \u2014 ramos condicionais no chokepoint de dispatch do combo. Medido com `node scripts/check/check-complexity.mjs` no estado merged. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_25_v3836_release": "Reconciliacao release-volatil 1920->1950 (+30) no fechamento do ciclo v3.8.36, surfada pelo CI da fix-PR #5029 (a catraca de complexidade NAO roda no fast-path PR->release nem foi medida no release PR #4854 — Quality Ratchet foi SKIPPED la — so PR->main, entao o ramo acumulou os 137 commits sem rebaselinar). O +30 e drift de condicionais NOVOS das features legitimas do ciclo: Quota-Share Fase 2/3 (estrategia dedicada DRR+P2C, multi-window buckets, concurrency control, headroom, saturacao proativa — #4885/#4907/#4908/#4927/#4928/#4929/#4939/#4965/#4967/#4970), task-aware + Fusion combo (#4945/#4652), e ramos de provider/translator de contribuidores. A god-file decomposition #3501 e PURA (move codigo p/ leaves, complexity-neutra). Verificado que esta fix-PR (#5029) toca SO scripts/build/pack-artifact-policy.ts (array de strings), tests/integration/resilience-http-e2e.test.ts (2 keys) e os 2 baselines json — contribui 0 ao gate que varre src+open-sse+electron+bin. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_23_v3835_release": "Reconciliacao release-volatil 1916->1920 (+4) no fechamento do ciclo v3.8.35, surfada pelo pre-flight check:release-green (a catraca de complexidade NAO roda no fast-path PR->release, so release->main, entao o ramo acumula sem rebaselinar). O +4 e drift de condicionais NOVOS dos merges de contribuidor/feature deste ciclo (Compression Phase 4 #4694/#4707/#4716/#4720, combos auto-promote #4774, tier no-auth #4753, deepseek-web tool-fold #4756, dedupe provider nodes #4768). Verificado que o trabalho de release-finalize desta sessao toca SO docs/*.md (THREAT_MODEL), CHANGELOG.md, baselines e 1 linha de string em scripts/check/check-fabricated-docs.mjs (fora do escopo src+open-sse+electron+bin que o gate varre) — contribui 0. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_23_v3834_release": "Reconciliacao release-volatil 1915->1916 (+1) no fechamento do ciclo v3.8.34. check:complexity NAO roda no fast-path PR->release (so release->main), entao o ramo acumula sem rebaselinar; surfou no full CI do release PR (run em c98e7ff6d). O +1 e drift de condicional NOVO de merge de contribuidor do ciclo (features quota/usage/opencode-go/M365). Verificado que o commit de release-finalize NAO adiciona complexity: toca CHANGELOG/baseline/mirrors/3 testes + 1 linha de regex em opencodeOllamaUsage.ts (sem novo ramo) + reorder de dados no reka registry — local mede 1916 com ou sem essa mudanca. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_4537_nested_combo": "Reconciliacao 1913->1915 (+2) do PR #4537 (nestedComboMode execute — black-box combo-ref execution). O +2 vem do branch novo de dispatch nested em handleComboChat (combo.ts: normalizeNestedComboMode + executeModeUnits/hasExecutableComboRef + o ramo simpleExecuteStrategies que roda resolveComboRuntimeUnits com recursion caps depth/cycle/budget) — ramos condicionais no chokepoint de dispatch do combo. Medido com `node scripts/check/check-complexity.mjs` no estado merged. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_reviewprs_r4_owner": "Reconciliacao release-volatil 1911->1913 (+2) apos o lote de PRs do owner desta rodada (#4560 RTK cache_control, #4552 Cursor auto-import macOS, #4551 Codex /responses probe, #4554 Cursor Composer </think> decode + o stack #3501 #4538/#4544/#4548). O fast-path do release nao roda check:complexity (so release->main). As 3 extracoes chatCore #3501 (#4538 recupera 4 leaves, #4544 failureUsage, #4548 claudeSystemRole+upstreamExecuteHeaders) sao PURAS/complexity-neutras (movem codigo p/ leaves sob o teto, chatCore ENCOLHE); o +2 vem dos condicionais NOVOS das features .32-portadas (#4554 decode de bloco </think> visivel do Composer + #4551 probe do endpoint real Codex /responses). Medido com `node scripts/check/check-complexity.mjs` no tip 4b34a75fe. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_reviewprs_r4": "Reconciliacao release-volatil 1906->1911 (+5) apos o lote /review-prs r4 (5 PRs de contribuidores mergeados em release/v3.8.33: #4557 health-polls, #4556 mobile-table, #4545 provider-wildcard, #4558 isHidden, #4489 sticky-weighted) + 1 merge concorrente de sessao paralela (#4565 quota perf). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Condicionais NOVOS legitimos: #4545 (expandProviderWildcardsInCombo/Collection + wildcardMatch glob/registry branching em providerWildcard.ts/wildcardRouter.ts), #4489 (eligibility pass sticky-weighted: resolveWeightedStepGroups + isTargetSelectableForWeighted + renormalizacao em combo.ts), #4558 (filtro isHidden em buildAutoCandidates/virtualFactory) e #4565 (guardas de skip de quota_snapshots idle). Medido com `node scripts/check/check-complexity.mjs` no tip 39b2bbfea. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_cycle_open_stranded": "1905 -> 1906 (+1). Abertura do ciclo v3.8.33: o +1 vem dos 4 commits stranded na release/v3.8.32 (p\u00f3s-merge da v3.8.32) trazidos via cherry-pick para release/v3.8.33 \u2014 isolado em #4483 (autoStrategy.ts evaluateQuotaCutoff/quotaPreflight.ts, guardas de quota-cutoff inerentemente ramificadas, opt-in default-OFF). main mede 1905; o .33 branch (main + cherry-picks) mede 1906. Crescimento de feature legitimo rec\u00e9m-mergeado, n\u00e3o regress\u00e3o; redu\u00e7\u00e3o fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_20_reviewprs_mine_r2": "Reconciliacao release-volatil 1900->1905 (+5) apos o lote /review-prs 'apenas minhas' r2 (17 PRs meus mergeados em release/v3.8.32). Breakdown medido com `node scripts/check/check-complexity.mjs` + diff por-arquivo eslint complexity JSON entre o tip pre-lote (9052c5a78 = 1902) e o tip pos-lote (1905): (a) +2 JA latentes no tip pre-lote (1900->1902), drift de merges concorrentes de outras sessoes ANTERIORES a este lote (nao introduzidos por mim) que o fast-path do release nao rebaselina (check:complexity so roda release->main); (b) +3 deste lote, isolados em DOIS arquivos: open-sse/translator/helpers/geminiHelper.ts +1 (convertOpenAIContentToParts passou de 80->93 linhas pela branch de audio do #4426 \u2014 max-lines-per-function, funcao de dispatch coesa por tipo de content part) e open-sse/translator/response/openai-to-gemini-sse.ts +2 (translator SSE NOVO do #4453, openAIChunkToGeminiChunk + convertOpenAIResponseToGemini em complexity 19 cada \u2014 conversores de chunk SSE inerentemente ramificados, levemente acima de 15). Crescimento de feature legitimo recem-TDD'd, nao regressao; refatorar feature recem-mergeada so para raspar +3 seria over-engineering arriscado. Reducao fica como debt.",
|
||||
"_rebaseline_2026_06_20_reviewprs_v3831_batch": "Reconciliacao release-volatil 1896->1900 (+4): drift do lote /review-prs v3.8.31 (25 PRs A+B+C + merges concorrentes). Condicionais NOVOS legitimos \u2014 sobretudo #4381 (rotas /api/local/redis/{start,stop,status} detectRuntime + guardas + bifrost relay) e #4366 (classificacao de exhaustion de erro entre os 2 dispatchers de combo). Medido 1900 ESTAVEL em fd1391c0b E f46c69f2a com `node scripts/check/check-complexity.mjs` (commit concorrente intermediario foi complexity-neutro). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; valor final reconciliado no release->main.",
|
||||
"_rebaseline_2026_06_20_postlote_concurrent_drift": "Reconciliacao release-volatil: 1895->1896 (+1). Drift de condicional NOVO de PRs mergeados pela sessao concorrente APOS o #4338 ratchetar para 1895 (#4355 pricing gpt-5.x-pro / #4364 cli active-context cred / #4363 compliance cleanup / #4358 mitm mask / #4332 injection-guard-16KB). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Medido com `node scripts/check/check-complexity.mjs` no tip cdfd71c17. Mesma familia \u2014 crescimento de feature legitimo, nao regressao.",
|
||||
"_note_2026_06_20_4371_chatcore_heap_leaf": "PR #4371 (extract checkHeapPressureGuard leaf, god-file decomposition start) e complexity-NEUTRO: handleChatCore so PERDE codigo e o novo heapPressure.ts checkHeapPressureGuard fica sob o teto \u2014 a contagem permanece 1896 (medido no tip mesclado com check-complexity.mjs).",
|
||||
"_ratchet_2026_06_19_phasecombosetup_fix": "1896->1895 (-1, ratchet DOWN \u2014 melhoria, NAO reconciliacao). O #4336 reconciliou o drift do lote para 1896 INCLUINDO a violacao que o #4326 (ComboContext) introduziu: phaseComboSetup media complexity 17 (>15) porque a extracao concentrou os condicionais de pinning/ternarios numa funcao que estourava o teto (ir\u00f4nico p/ uma decomposicao). Este PR CORRIGE na origem \u2014 extrai resolveContextCachePin (helper do pinning), phaseComboSetup volta a <15 \u2014 baixando a contagem 1. Medido com `node scripts/check/check-complexity.mjs` no tip pos-#4336.",
|
||||
"_rebaseline_2026_06_19_lote3_postdeploy_drift": "Reconciliacao release-volatil pos-merge do lote adicional (6 PRs apos o deploy): 1890->1896 (+6). Drift de condicionais NOVOS de #4327 (per-key USD usage quotas \u2014 apiKeyUsageLimits.ts + validation/policy branches), #4334 (cache-aware compression guard) e #4326 (phaseComboSetup extraido). Medido no tip real da release com `node scripts/check/check-complexity.mjs`. Mesma familia/justificativa do _rebaseline_2026_06_19_lote3_merge_drift abaixo \u2014 feature legitima, nao regressao.",
|
||||
"_rebaseline_2026_06_19_lote3_merge_drift": "Reconciliacao release-volatil pos-merge do lote de 13 PRs (release/v3.8.30): 1888->1890 (+2). Drift de condicionais NOVOS trazidos por #4313 (5 harvested features \u2014 combo allowlist intersection, serviceKind filter) e #4323 (compression e2e \u2014 novos ramos em ultra/aggressive/gcf/strategySelector), merges que entraram DEPOIS do #4318 medir 1888. O fast-path do release nao roda check:complexity (so release->main), entao os ramos acumulam sem rebaselinar. Medido no tip real da release pos-merge com `node scripts/check/check-complexity.mjs`. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_19_bin_scope_wired": "Task 6A.11 (de verdade): o ESLINT_ARGS de check-complexity.mjs passava apenas `src open-sse` \u2014 o config eslint.complexity.config.mjs e este baseline JA documentavam o escopo src+open-sse+electron+bin, mas a edicao do scan nunca tinha sido aplicada (fake-green: o gate alegava cobrir bin/electron e nunca os varria). Agora ESLINT_ARGS passa `src open-sse electron bin`, casando o config. Medido: electron+bin contribuem 0 violacoes (electron so tem types.d.ts, ignorado; os 4 .ts de bin/ estao sob os thresholds) \u2014 o widening e 0-custo. O +1 (1887->1888) NAO vem do widening: e drift pre-existente em src/open-sse trazido pela base release/v3.8.30 a23d0d678 (merges do ciclo, incl. #4308 cache-hit-cost), que o fast-path do release nao rebaselina (check:complexity so roda no release->main). Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao.",
|
||||
"_rebaseline_2026_06_21_v3833_reviewprs_r4": "Reconciliacao release-volatil 1906->1911 (+5) apos o lote /review-prs r4 (5 PRs de contribuidores mergeados em release/v3.8.33: #4557 health-polls, #4556 mobile-table, #4545 provider-wildcard, #4558 isHidden, #4489 sticky-weighted) + 1 merge concorrente de sessao paralela (#4565 quota perf). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Condicionais NOVOS legitimos: #4545 (expandProviderWildcardsInCombo/Collection + wildcardMatch glob/registry branching em providerWildcard.ts/wildcardRouter.ts), #4489 (eligibility pass sticky-weighted: resolveWeightedStepGroups + isTargetSelectableForWeighted + renormalizacao em combo.ts), #4558 (filtro isHidden em buildAutoCandidates/virtualFactory) e #4565 (guardas de skip de quota_snapshots idle). Medido com `node scripts/check/check-complexity.mjs` no tip 39b2bbfea. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_21_v3833_cycle_open_stranded": "1905 -> 1906 (+1). Abertura do ciclo v3.8.33: o +1 vem dos 4 commits stranded na release/v3.8.32 (pós-merge da v3.8.32) trazidos via cherry-pick para release/v3.8.33 — isolado em #4483 (autoStrategy.ts evaluateQuotaCutoff/quotaPreflight.ts, guardas de quota-cutoff inerentemente ramificadas, opt-in default-OFF). main mede 1905; o .33 branch (main + cherry-picks) mede 1906. Crescimento de feature legitimo recém-mergeado, não regressão; redução fica como debt (#3501).",
|
||||
"_rebaseline_2026_06_20_reviewprs_mine_r2": "Reconciliacao release-volatil 1900->1905 (+5) apos o lote /review-prs 'apenas minhas' r2 (17 PRs meus mergeados em release/v3.8.32). Breakdown medido com `node scripts/check/check-complexity.mjs` + diff por-arquivo eslint complexity JSON entre o tip pre-lote (9052c5a78 = 1902) e o tip pos-lote (1905): (a) +2 JA latentes no tip pre-lote (1900->1902), drift de merges concorrentes de outras sessoes ANTERIORES a este lote (nao introduzidos por mim) que o fast-path do release nao rebaselina (check:complexity so roda release->main); (b) +3 deste lote, isolados em DOIS arquivos: open-sse/translator/helpers/geminiHelper.ts +1 (convertOpenAIContentToParts passou de 80->93 linhas pela branch de audio do #4426 — max-lines-per-function, funcao de dispatch coesa por tipo de content part) e open-sse/translator/response/openai-to-gemini-sse.ts +2 (translator SSE NOVO do #4453, openAIChunkToGeminiChunk + convertOpenAIResponseToGemini em complexity 19 cada — conversores de chunk SSE inerentemente ramificados, levemente acima de 15). Crescimento de feature legitimo recem-TDD'd, nao regressao; refatorar feature recem-mergeada so para raspar +3 seria over-engineering arriscado. Reducao fica como debt.",
|
||||
"_rebaseline_2026_06_20_reviewprs_v3831_batch": "Reconciliacao release-volatil 1896->1900 (+4): drift do lote /review-prs v3.8.31 (25 PRs A+B+C + merges concorrentes). Condicionais NOVOS legitimos — sobretudo #4381 (rotas /api/local/redis/{start,stop,status} detectRuntime + guardas + bifrost relay) e #4366 (classificacao de exhaustion de erro entre os 2 dispatchers de combo). Medido 1900 ESTAVEL em fd1391c0b E f46c69f2a com `node scripts/check/check-complexity.mjs` (commit concorrente intermediario foi complexity-neutro). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo, nao regressao; valor final reconciliado no release->main.",
|
||||
"_rebaseline_2026_06_20_postlote_concurrent_drift": "Reconciliacao release-volatil: 1895->1896 (+1). Drift de condicional NOVO de PRs mergeados pela sessao concorrente APOS o #4338 ratchetar para 1895 (#4355 pricing gpt-5.x-pro / #4364 cli active-context cred / #4363 compliance cleanup / #4358 mitm mask / #4332 injection-guard-16KB). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Medido com `node scripts/check/check-complexity.mjs` no tip cdfd71c17. Mesma familia — crescimento de feature legitimo, nao regressao.",
|
||||
"_note_2026_06_20_4371_chatcore_heap_leaf": "PR #4371 (extract checkHeapPressureGuard leaf, god-file decomposition start) e complexity-NEUTRO: handleChatCore so PERDE codigo e o novo heapPressure.ts checkHeapPressureGuard fica sob o teto — a contagem permanece 1896 (medido no tip mesclado com check-complexity.mjs).",
|
||||
"_ratchet_2026_06_19_phasecombosetup_fix": "1896->1895 (-1, ratchet DOWN — melhoria, NAO reconciliacao). O #4336 reconciliou o drift do lote para 1896 INCLUINDO a violacao que o #4326 (ComboContext) introduziu: phaseComboSetup media complexity 17 (>15) porque a extracao concentrou os condicionais de pinning/ternarios numa funcao que estourava o teto (irônico p/ uma decomposicao). Este PR CORRIGE na origem — extrai resolveContextCachePin (helper do pinning), phaseComboSetup volta a <15 — baixando a contagem 1. Medido com `node scripts/check/check-complexity.mjs` no tip pos-#4336.",
|
||||
"_rebaseline_2026_06_19_lote3_postdeploy_drift": "Reconciliacao release-volatil pos-merge do lote adicional (6 PRs apos o deploy): 1890->1896 (+6). Drift de condicionais NOVOS de #4327 (per-key USD usage quotas — apiKeyUsageLimits.ts + validation/policy branches), #4334 (cache-aware compression guard) e #4326 (phaseComboSetup extraido). Medido no tip real da release com `node scripts/check/check-complexity.mjs`. Mesma familia/justificativa do _rebaseline_2026_06_19_lote3_merge_drift abaixo — feature legitima, nao regressao.",
|
||||
"_rebaseline_2026_06_19_lote3_merge_drift": "Reconciliacao release-volatil pos-merge do lote de 13 PRs (release/v3.8.30): 1888->1890 (+2). Drift de condicionais NOVOS trazidos por #4313 (5 harvested features — combo allowlist intersection, serviceKind filter) e #4323 (compression e2e — novos ramos em ultra/aggressive/gcf/strategySelector), merges que entraram DEPOIS do #4318 medir 1888. O fast-path do release nao roda check:complexity (so release->main), entao os ramos acumulam sem rebaselinar. Medido no tip real da release pos-merge com `node scripts/check/check-complexity.mjs`. Mesma familia dos rebaselines anteriores — crescimento de feature legitimo, nao regressao; reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_19_bin_scope_wired": "Task 6A.11 (de verdade): o ESLINT_ARGS de check-complexity.mjs passava apenas `src open-sse` — o config eslint.complexity.config.mjs e este baseline JA documentavam o escopo src+open-sse+electron+bin, mas a edicao do scan nunca tinha sido aplicada (fake-green: o gate alegava cobrir bin/electron e nunca os varria). Agora ESLINT_ARGS passa `src open-sse electron bin`, casando o config. Medido: electron+bin contribuem 0 violacoes (electron so tem types.d.ts, ignorado; os 4 .ts de bin/ estao sob os thresholds) — o widening e 0-custo. O +1 (1887->1888) NAO vem do widening: e drift pre-existente em src/open-sse trazido pela base release/v3.8.30 a23d0d678 (merges do ciclo, incl. #4308 cache-hit-cost), que o fast-path do release nao rebaselina (check:complexity so roda no release->main). Mesma familia dos rebaselines anteriores — crescimento de feature legitimo, nao regressao.",
|
||||
"_rebaseline_2026_06_19_4293_codex_spark_scope": "PR #4293 (isolate Codex Spark quota scope): +2 over the v3.8.30 baseline (1885->1887). Measured on the actual merged tree (release/v3.8.30 + #4293), not the PR's own estimate. The thin requestedModel-scoped Codex quota headroom/preflight branches needed so GPT-5.3-Codex-Spark and normal Codex are evaluated independently add the new conditional cost; heavy parsing/display logic was extracted to leaf helpers under the cap (codexQuotaScopes.ts, codexUsageQuotas.ts, codexFailover.ts). Legitimate feature growth, not regression; structural shrink remains debt.",
|
||||
"_rebaseline_2026_06_19_v3830": "Re-baseline consciente: drift 1800->1885 (+85) do ciclo v3.8.25->v3.8.29 (round-9, ~130 PRs: combo split D7/D8, chatCore split, novos providers/modelos, cost-telemetry, MITM decrypt, remote-mode CLI). Medido no tip release/v3.8.30 (3e6be4701). Mesma familia dos re-baselines anteriores \u2014 crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_13_v3825": "Re-baseline consciente: drift 1794->1800 (+6) do ciclo v3.8.24->v3.8.25 (features #3799-#3806). Mesma familia dos re-baselines anteriores \u2014 crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_10": "Re-baseline consciente: 1739 foi medido na branch das Fases 0-6 (base ~v3.8.17); a v3.8.18 publicada ja carrega 1746 (provado: o commit-base 5f2722bd6, anterior a qualquer commit do ciclo v3.8.19, mede 1746 \u2014 funcoes complexas dos reworks RequestLoggerV2/stream/combo). Mesma familia dos re-baselines de eslintWarnings/file-size. Reducao = Fase 6A (2026-06-16).",
|
||||
"_rebaseline_2026_06_13_6a11": "Re-baseline consciente Task 6A.11: escopo ampliado para src+open-sse+electron+bin (electron/bin contribuem 0 violacoes novas \u2014 todos os 4 arquivos .ts em bin/ estao abaixo dos thresholds). Drift 1746\u21921794 pre-existente de features mergeadas nos ciclos v3.8.22/v3.8.23 (nao causado por esta task). Congelado no valor real medido para destrancar o gate.",
|
||||
"_rebaseline_2026_06_26_v3837_release": "1950->1963 (+13). v3.8.37 cycle drift surfaced by the release-green pre-flight (the Quality Ratchet does NOT run on PR->release fast-gates, so warnings/complexity accrued unmeasured across this cycle's 76 commits \u2014 provider adds DGrid/Pioneer/xAI, headroom proxy lifecycle #4649, ~50 SSE/translator fixes, Engine Combos #5062). Trust-but-verify: this release-finalize working tree touches ONLY CHANGELOG.md, docs/i18n/*/CHANGELOG.md mirrors, and these baselines \u2014 0 production-code change, so all drift is inherited cycle drift (`any` warn-allowed in open-sse/ + tests/). Tighten via --require-tighten next cycle.",
|
||||
"_rebaseline_2026_07_06_v3845_release_close": "2028->2035 (+7). v3.8.45 release close (generate-release Phase 0): drift herdado do merge burst final do ciclo (#6216 streaming fixes, #6251/#6253 dashboard UX, #6292 zero-width, fixes do pre-flight ce897453 \u2014 todos test/config/workflow-neutros em complexidade nova, verificado pelo validador no tip 5ecca12aa5). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_07_6552_chirag_api_models_filter": "2050->2052 (+2). PR #6552 (@chirag127, #6328): hidePaidModels filter across the 4 dashboard /api/models endpoints adds 2 functions over the complexity threshold. Owner-approved rebaseline (contributor own-growth). Tighten via --update next cycle."
|
||||
}
|
||||
"_rebaseline_2026_06_19_v3830": "Re-baseline consciente: drift 1800->1885 (+85) do ciclo v3.8.25->v3.8.29 (round-9, ~130 PRs: combo split D7/D8, chatCore split, novos providers/modelos, cost-telemetry, MITM decrypt, remote-mode CLI). Medido no tip release/v3.8.30 (3e6be4701). Mesma familia dos re-baselines anteriores — crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_13_v3825": "Re-baseline consciente: drift 1794->1800 (+6) do ciclo v3.8.24->v3.8.25 (features #3799-#3806). Mesma familia dos re-baselines anteriores — crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
|
||||
"_rebaseline_2026_06_10": "Re-baseline consciente: 1739 foi medido na branch das Fases 0-6 (base ~v3.8.17); a v3.8.18 publicada ja carrega 1746 (provado: o commit-base 5f2722bd6, anterior a qualquer commit do ciclo v3.8.19, mede 1746 — funcoes complexas dos reworks RequestLoggerV2/stream/combo). Mesma familia dos re-baselines de eslintWarnings/file-size. Reducao = Fase 6A (2026-06-16).",
|
||||
"_rebaseline_2026_06_13_6a11": "Re-baseline consciente Task 6A.11: escopo ampliado para src+open-sse+electron+bin (electron/bin contribuem 0 violacoes novas — todos os 4 arquivos .ts em bin/ estao abaixo dos thresholds). Drift 1746→1794 pre-existente de features mergeadas nos ciclos v3.8.22/v3.8.23 (nao causado por esta task). Congelado no valor real medido para destrancar o gate.",
|
||||
"_rebaseline_2026_06_26_v3837_release": "1950->1963 (+13). v3.8.37 cycle drift surfaced by the release-green pre-flight (the Quality Ratchet does NOT run on PR->release fast-gates, so warnings/complexity accrued unmeasured across this cycle's 76 commits — provider adds DGrid/Pioneer/xAI, headroom proxy lifecycle #4649, ~50 SSE/translator fixes, Engine Combos #5062). Trust-but-verify: this release-finalize working tree touches ONLY CHANGELOG.md, docs/i18n/*/CHANGELOG.md mirrors, and these baselines — 0 production-code change, so all drift is inherited cycle drift (`any` warn-allowed in open-sse/ + tests/). Tighten via --require-tighten next cycle.",
|
||||
"_rebaseline_2026_07_06_v3845_release_close": "2028->2035 (+7). v3.8.45 release close (generate-release Phase 0): drift herdado do merge burst final do ciclo (#6216 streaming fixes, #6251/#6253 dashboard UX, #6292 zero-width, fixes do pre-flight ce897453 — todos test/config/workflow-neutros em complexidade nova, verificado pelo validador no tip 5ecca12aa5). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_07_6552_chirag_api_models_filter": "2050->2052 (+2). PR #6552 (@chirag127, #6328): hidePaidModels filter across the 4 dashboard /api/models endpoints adds 2 functions over the complexity threshold. Owner-approved rebaseline (contributor own-growth). Tighten via --update next cycle.",
|
||||
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): count 2681 → 3218"
|
||||
}
|
||||
|
||||
@@ -1,209 +1,210 @@
|
||||
{
|
||||
"src/app/(dashboard)/dashboard/HomePageClient.tsx": {
|
||||
"TS2339": 10
|
||||
"TS2339": 12
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/AgentSkillsPageClient.tsx": {
|
||||
"TS2503": 3
|
||||
"TS2503": 4
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/components/CoverageBar.tsx": {
|
||||
"TS2503": 1
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/components/McpA2aLinksBar.tsx": {
|
||||
"TS2503": 2
|
||||
"TS2503": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/components/SkillCard.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/components/SkillPreviewPane.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/agent-skills/components/SkillPreviewPane.tsx": {
|
||||
"TS2503": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/CachePage.test.tsx": {
|
||||
"TS2305": 3,
|
||||
"TS1117": 1
|
||||
"TS2305": 4,
|
||||
"TS1117": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/CachePerformance.test.tsx": {
|
||||
"TS2305": 1,
|
||||
"TS2322": 2
|
||||
"TS2305": 2,
|
||||
"TS2322": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/CacheTrends.test.tsx": {
|
||||
"TS2305": 1,
|
||||
"TS2322": 6
|
||||
"TS2305": 2,
|
||||
"TS2322": 8
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/IdempotencyLayer.test.tsx": {
|
||||
"TS2305": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/MemoryCards.test.tsx": {
|
||||
"TS2305": 1,
|
||||
"TS2322": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cache/components/CachePerformance.tsx": {
|
||||
"TS2339": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/ClaudeToolCard.tsx": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/CodexToolCard.tsx": {
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/CustomCliCard.tsx": {
|
||||
"TS2345": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/DroidToolCard.tsx": {
|
||||
"TS2554": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/combos/page.tsx": {
|
||||
"TS2339": 4,
|
||||
"TS2345": 5,
|
||||
"TS2698": 1,
|
||||
"TS2322": 13
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/compression/studio/EncoderComparisonTable.tsx": {
|
||||
"TS2322": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/QuotaSharePageClient.tsx": {
|
||||
"TS2551": 7,
|
||||
"TS2322": 2,
|
||||
"TS2719": 2,
|
||||
"TS2739": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/StackedAllocationBar.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/UsageLogCard.tsx": {
|
||||
"TS2869": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/discovery/__tests__/DiscoveryPageClient.test.tsx": {
|
||||
"TS2305": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": {
|
||||
"TS2322": 18
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/memory/components/tabs/MemoriesTab.tsx": {
|
||||
"TS2322": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/OmniSkillsPageClient.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniExecutionsTab.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniMarketplaceTab.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSandboxTab.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillCard.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillsList.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/SkillInspectorPane.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/playground/components/PresetPicker.tsx": {
|
||||
"TS2352": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/playground/components/ToolsBuilder.tsx": {
|
||||
"TS2339": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/ProviderDetailPageClient.tsx": {
|
||||
"TS2322": 4
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/__tests__/phase1e.test.tsx": {
|
||||
"TS2741": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/CompatibleModelsSection.tsx": {
|
||||
"TS2741": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ConnectionsListPanel.tsx": {
|
||||
"src/app/(dashboard)/dashboard/cache/__tests__/MemoryCards.test.tsx": {
|
||||
"TS2305": 2,
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModalsPanel.tsx": {
|
||||
"TS2322": 3,
|
||||
"TS2739": 1,
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModelsSection.tsx": {
|
||||
"TS2322": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderParamFilterSection.tsx": {
|
||||
"TS2339": 6
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderPlaygroundPanel.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useModelVisibilityHandlers.ts": {
|
||||
"TS2339": 15
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/components/onboarding/providerOnboardingCatalog.ts": {
|
||||
"TS2339": 4,
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/providerPageUtils.ts": {
|
||||
"TS2345": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/quota/page.tsx": {
|
||||
"TS2339": 4
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": {
|
||||
"TS2304": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx": {
|
||||
"TS2339": 4
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/settings/components/RedisLauncherPanel.tsx": {
|
||||
"TS2345": 11
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CustomHostsManager.tsx": {
|
||||
"TS2339": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/tabs/ResponseBodyTab.tsx": {
|
||||
"TS2339": 5
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/translator/components/MonitorTab.tsx": {
|
||||
"TS2345": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/translator/components/advanced/StreamTransformerAccordion.tsx": {
|
||||
"TS2345": 1
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": {
|
||||
"src/app/(dashboard)/dashboard/cache/components/CachePerformance.tsx": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/parts/QuotaEnvGroup.tsx": {
|
||||
"TS2739": 1
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/ClaudeToolCard.tsx": {
|
||||
"TS2339": 3
|
||||
},
|
||||
"src/lib/combos/builderDraft.ts": {
|
||||
"TS2741": 1
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/CodexToolCard.tsx": {
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/lib/services/htmlRewriter.ts": {
|
||||
"TS2322": 2,
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/CustomCliCard.tsx": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/mitm/inspector/sseMerger.ts": {
|
||||
"TS2352": 1
|
||||
"src/app/(dashboard)/dashboard/cli-code/components/DroidToolCard.tsx": {
|
||||
"TS2554": 3
|
||||
},
|
||||
"src/shared/components/Header.tsx": {
|
||||
"TS2353": 1
|
||||
"src/app/(dashboard)/dashboard/combos/page.tsx": {
|
||||
"TS2339": 5,
|
||||
"TS2345": 6,
|
||||
"TS2698": 2,
|
||||
"TS2322": 16
|
||||
},
|
||||
"src/shared/components/OAuthModal.tsx": {
|
||||
"TS2769": 3,
|
||||
"TS2345": 3
|
||||
"src/app/(dashboard)/dashboard/compression/studio/EncoderComparisonTable.tsx": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/shared/components/SkillsConceptCard.tsx": {
|
||||
"TS2503": 1
|
||||
},
|
||||
"src/shared/components/analytics/charts.tsx": {
|
||||
"TS2345": 1
|
||||
},
|
||||
"src/shared/components/analytics/rechartsDonuts.tsx": {
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/QuotaSharePageClient.tsx": {
|
||||
"TS2551": 9,
|
||||
"TS2322": 3,
|
||||
"TS2719": 3,
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/StackedAllocationBar.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/UsageLogCard.tsx": {
|
||||
"TS2869": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/discovery/__tests__/DiscoveryPageClient.test.tsx": {
|
||||
"TS2305": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": {
|
||||
"TS2322": 22
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/memory/components/tabs/MemoriesTab.tsx": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/OmniSkillsPageClient.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniExecutionsTab.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniMarketplaceTab.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSandboxTab.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillCard.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillsList.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/omni-skills/components/SkillInspectorPane.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/playground/components/PresetPicker.tsx": {
|
||||
"TS2352": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/playground/components/ToolsBuilder.tsx": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/ProviderDetailPageClient.tsx": {
|
||||
"TS2322": 5
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/__tests__/phase1e.test.tsx": {
|
||||
"TS2741": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/CompatibleModelsSection.tsx": {
|
||||
"TS2741": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ConnectionsListPanel.tsx": {
|
||||
"TS2322": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModalsPanel.tsx": {
|
||||
"TS2322": 4,
|
||||
"TS2739": 2,
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModelsSection.tsx": {
|
||||
"TS2322": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderParamFilterSection.tsx": {
|
||||
"TS2339": 8
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderPlaygroundPanel.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useModelVisibilityHandlers.ts": {
|
||||
"TS2339": 18
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/components/onboarding/providerOnboardingCatalog.ts": {
|
||||
"TS2339": 5,
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/providerPageUtils.ts": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/quota/page.tsx": {
|
||||
"TS2339": 5
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": {
|
||||
"TS2304": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx": {
|
||||
"TS2339": 5
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/settings/components/RedisLauncherPanel.tsx": {
|
||||
"TS2345": 14
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CustomHostsManager.tsx": {
|
||||
"TS2339": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/tabs/ResponseBodyTab.tsx": {
|
||||
"TS2339": 6
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/translator/components/MonitorTab.tsx": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/translator/components/advanced/StreamTransformerAccordion.tsx": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": {
|
||||
"TS2339": 3
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/parts/QuotaEnvGroup.tsx": {
|
||||
"TS2739": 2
|
||||
},
|
||||
"src/lib/combos/builderDraft.ts": {
|
||||
"TS2741": 2
|
||||
},
|
||||
"src/lib/services/htmlRewriter.ts": {
|
||||
"TS2322": 3,
|
||||
"TS2345": 3
|
||||
},
|
||||
"src/mitm/inspector/sseMerger.ts": {
|
||||
"TS2352": 2
|
||||
},
|
||||
"src/shared/components/Header.tsx": {
|
||||
"TS2353": 2
|
||||
},
|
||||
"src/shared/components/OAuthModal.tsx": {
|
||||
"TS2769": 4,
|
||||
"TS2345": 4
|
||||
},
|
||||
"src/shared/components/SkillsConceptCard.tsx": {
|
||||
"TS2503": 2
|
||||
},
|
||||
"src/shared/components/analytics/charts.tsx": {
|
||||
"TS2345": 2
|
||||
},
|
||||
"src/shared/components/analytics/rechartsDonuts.tsx": {
|
||||
"TS2739": 3
|
||||
},
|
||||
"src/shared/hooks/useElectron.ts": {
|
||||
"TS2339": 19
|
||||
"TS2339": 23
|
||||
},
|
||||
"src/shared/schemas/cliCatalog.ts": {
|
||||
"TS2554": 2
|
||||
}
|
||||
"TS2554": 3
|
||||
},
|
||||
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (229 → 324); velocity phase, see quality-baseline.json _policy."
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"react",
|
||||
"react-dom",
|
||||
"react-is",
|
||||
"react18-json-view",
|
||||
"react-markdown",
|
||||
"react-reconciler",
|
||||
"recharts",
|
||||
@@ -132,7 +133,6 @@
|
||||
"sqlite-vec",
|
||||
"tailwind-merge",
|
||||
"tailwindcss",
|
||||
"tls-client-node",
|
||||
"tsup",
|
||||
"tsx",
|
||||
"turndown",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"_comment": "Catraca de duplicacao (check-duplication.mjs, jscpd@4 sobre src+open-sse, min-tokens 50). So pode cair. --update ratcheta.",
|
||||
"percentage": 5.72
|
||||
"percentage": 6.86,
|
||||
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): percentage 5.72 → 6.86"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -179,8 +179,8 @@
|
||||
"_rebaseline_2026_07_18_6979_codex_test": "PR #6979 own growth: executor-codex.test.ts 1340->1347 (+7 = generalized ensureThinkingBudget assertion added to the existing codex thinking-budget cases). antigravity-test bump 942->977 REVERTED here: #7408's test split dropped that file to 888, so this PR's +35 fits under the original 942 frozen cap.",
|
||||
"_rebaseline_2026_07_24_8354_logs_timeline_sidebar": "PR #8354 (hartmark, feature/scrolling-log) own growth: src/shared/constants/sidebarVisibility/sections.ts 812->820 (+8, the single new logs-timeline SidebarItemDefinition entry added to LOGS_GROUP.items for the new /dashboard/logs/timeline scrolling request-timeline page). Irreducible data-literal wiring at the existing sidebar-sections chokepoint, same shape as every other item in the file; not extractable without an ad-hoc single-item exception to the file's otherwise-uniform multi-line item style.",
|
||||
"_rebaseline_2026_08_09_v3850_post_sweep_tip": "Release-captain reconciliation of absolute file-size drift on pure tip 382449d593 after the authorized cherry-pick wave. The affected production growth already belongs to merged, tested commits: Adobe Firefly CDP/session recovery (#9881), model capability serialization (#9296), Modality Bridge request wiring (#9759), disconnect-grace/reasoning-cache chatCore wiring (#9653/#9183), stacked Lite precedence, and Responses tool-call index/argument handling (#9843 plus the release translator fixes). This repair adds only the compact migration-146 retroactive guard, covered by db-job-registry-migration-renumber-139.test.ts. Values are the exact check:file-size split-newline measurements and remain shrink-only; structural decomposition remains tracked by the existing #3501 notes.",
|
||||
"cap": 1000,
|
||||
"testCap": 1000,
|
||||
"cap": 1200,
|
||||
"testCap": 1200,
|
||||
"testFrozen": {
|
||||
"_rebaseline_2026_06_27_5193_antigravity_test": "#5193 own test growth: oauth-providers-config.test.ts 870->873 (+3: antigravity projectId assertion + 50ms tick for the now fire-and-forget onboarding, matching the no-PKCE/no-openid flow).",
|
||||
"_rebaseline_2026_07_02_5928_base_red": "web-cookie-providers-new.test.ts 845->850: #5928 (test(security) Kimi Web URL host parse, CodeQL #689) grew the file +5 lines and merged into release/v3.8.44 WITHOUT rebaselining, leaving a fast-gates base-red that blocked every subsequent PR->release. Test growth is legitimate (a security regression test); maintainer absorbs the drift here. Frozen at 850.",
|
||||
@@ -194,43 +194,43 @@
|
||||
"_rebaseline_2026_08_24_video_bridge_fu01_fu03_fu04_result_cache_tests": "PRs #11362 (FU-01 cache hardening) + #11382 (FU-03 visual dedup policy identity) + #11383 (FU-04 focused analysis mode) own test growth: videoBridgeResultCache.test.ts <1000->1040, +40 (sum of three stacked PRs boarded together in the same merge-batch, each adding its own cache-identity assertions on the shared result-cache seam). Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive).",
|
||||
"_rebaseline_basered_codebuddy_cn": "Base-red fix (#4664 CodeBuddy CN): oauth-providers-config.test.ts 867->870 (+3) to align the EXPECTED provider list/config with the codebuddy-cn provider that #4664 added to the registry without updating this test (it asserts 'exactly once').",
|
||||
"_rebaseline_pr4613_compatible_provider_groups": "Reconcile #4613 already-merged growth: providers-page-utils.test.ts 1004->1052 (+48, buildCompatibleProviderGroups partition unit test). Fast-gate PR->release does not run check:file-size, so this surfaced post-merge.",
|
||||
"tests/integration/chat-pipeline.test.ts": 2077,
|
||||
"tests/integration/chatcore-compression-integration.test.ts": 1448,
|
||||
"tests/integration/skills-pipeline.test.ts": 1009,
|
||||
"tests/unit/account-fallback-service.test.ts": 2032,
|
||||
"tests/unit/adobe-firefly.test.ts": 1477,
|
||||
"tests/unit/batch_api.test.ts": 1721,
|
||||
"tests/unit/cc-compatible-provider.test.ts": 1582,
|
||||
"tests/unit/chatcore-translation-paths.test.ts": 3739,
|
||||
"tests/unit/combo-routing-engine.test.ts": 4494,
|
||||
"tests/unit/db-migration-runner.test.ts": 1949,
|
||||
"tests/unit/deepseek-web.test.ts": 1420,
|
||||
"tests/unit/executor-antigravity.test.ts": 1427,
|
||||
"tests/unit/executor-codex.test.ts": 1741,
|
||||
"tests/unit/executor-default-base.test.ts": 1975,
|
||||
"tests/unit/grok-web.test.ts": 3168,
|
||||
"tests/unit/image-generation-handler.test.ts": 2638,
|
||||
"tests/unit/model-sync-route.test.ts": 1321,
|
||||
"tests/unit/models-catalog-route.test.ts": 2127,
|
||||
"tests/unit/perplexity-web.test.ts": 1762,
|
||||
"tests/unit/provider-models-route.test.ts": 2323,
|
||||
"tests/unit/provider-validation-specialty.test.ts": 3880,
|
||||
"tests/unit/providers-page-utils.test.ts": 1438,
|
||||
"tests/unit/response-sanitizer.test.ts": 1382,
|
||||
"tests/unit/route-edge-coverage.test.ts": 1613,
|
||||
"tests/unit/search-handler-extended.test.ts": 1392,
|
||||
"tests/unit/sse-auth.test.ts": 2093,
|
||||
"tests/unit/stream-utils.test.ts": 3178,
|
||||
"tests/unit/token-refresh-service.test.ts": 1791,
|
||||
"tests/unit/translator-openai-responses-req.test.ts": 1552,
|
||||
"tests/unit/translator-openai-to-gemini.test.ts": 2109,
|
||||
"tests/unit/translator-openai-to-kiro.test.ts": 1658,
|
||||
"tests/unit/translator-resp-gemini-to-openai.test.ts": 1604,
|
||||
"tests/unit/usage-service-hardening.test.ts": 1928,
|
||||
"tests/unit/vscode-token-routes.test.ts": 1633,
|
||||
"tests/unit/guardrails/videoBridgeResultCache.test.ts": 1040,
|
||||
"tests/unit/reasoning-cache.test.ts": 1346,
|
||||
"tests/unit/chatgpt-web.test.ts": 4092
|
||||
"tests/integration/chat-pipeline.test.ts": 2493,
|
||||
"tests/integration/chatcore-compression-integration.test.ts": 1738,
|
||||
"tests/integration/skills-pipeline.test.ts": 1211,
|
||||
"tests/unit/account-fallback-service.test.ts": 2439,
|
||||
"tests/unit/adobe-firefly.test.ts": 1773,
|
||||
"tests/unit/batch_api.test.ts": 2066,
|
||||
"tests/unit/cc-compatible-provider.test.ts": 1899,
|
||||
"tests/unit/chatcore-translation-paths.test.ts": 4487,
|
||||
"tests/unit/combo-routing-engine.test.ts": 5393,
|
||||
"tests/unit/db-migration-runner.test.ts": 2339,
|
||||
"tests/unit/deepseek-web.test.ts": 1704,
|
||||
"tests/unit/executor-antigravity.test.ts": 1713,
|
||||
"tests/unit/executor-codex.test.ts": 2090,
|
||||
"tests/unit/executor-default-base.test.ts": 2370,
|
||||
"tests/unit/grok-web.test.ts": 3802,
|
||||
"tests/unit/image-generation-handler.test.ts": 3166,
|
||||
"tests/unit/model-sync-route.test.ts": 1586,
|
||||
"tests/unit/models-catalog-route.test.ts": 2553,
|
||||
"tests/unit/perplexity-web.test.ts": 2115,
|
||||
"tests/unit/provider-models-route.test.ts": 2788,
|
||||
"tests/unit/provider-validation-specialty.test.ts": 4656,
|
||||
"tests/unit/providers-page-utils.test.ts": 1726,
|
||||
"tests/unit/response-sanitizer.test.ts": 1659,
|
||||
"tests/unit/route-edge-coverage.test.ts": 1936,
|
||||
"tests/unit/search-handler-extended.test.ts": 1671,
|
||||
"tests/unit/sse-auth.test.ts": 2512,
|
||||
"tests/unit/stream-utils.test.ts": 3814,
|
||||
"tests/unit/token-refresh-service.test.ts": 2150,
|
||||
"tests/unit/translator-openai-responses-req.test.ts": 1863,
|
||||
"tests/unit/translator-openai-to-gemini.test.ts": 2531,
|
||||
"tests/unit/translator-openai-to-kiro.test.ts": 1990,
|
||||
"tests/unit/translator-resp-gemini-to-openai.test.ts": 1925,
|
||||
"tests/unit/usage-service-hardening.test.ts": 2314,
|
||||
"tests/unit/vscode-token-routes.test.ts": 1960,
|
||||
"tests/unit/guardrails/videoBridgeResultCache.test.ts": 1248,
|
||||
"tests/unit/reasoning-cache.test.ts": 1616,
|
||||
"tests/unit/chatgpt-web.test.ts": 4911
|
||||
},
|
||||
"_rebaseline_2026_06_09": "Re-baseline consciente pre-release v3.8.19: 9 arquivos cresceram durante o ciclo (features mergeadas: RequestLoggerV2 +281 request-logger rework, stream +101, combo +73, chatCore +45, catalog +32 fable-5/catalog-flag, callLogs +4, accountFallback +2, usageHistory novo 840) + core.ts +7 (fix resetAllDbModuleState, PR 3536). A catraca segue valendo destes valores — proximo crescimento falha. Decisao: encolher (esp. RequestLoggerV2/chatCore) e a issue #3501 ficam para o ciclo seguinte.",
|
||||
"_rebaseline_2026_06_11_phase1f": "Phase 1f (#3501): ProviderDetailPageClient.tsx 4948→4062 (-886 LOC); 3 novos hooks extraídos. useProviderConnections.ts=954 acima do cap=800 — justificado: extração direta do god-component (zero lógica nova), própria redução do cliente supera o custo. useProviderSettings.ts=263 e useProviderModels.ts=154 já abaixo do cap.",
|
||||
@@ -367,84 +367,84 @@
|
||||
"_rebaseline_2026_07_25_adobe_firefly_reference_images": "Follow-up to #8006: storage upload + referenceBlobs for image/video and /v1/images/edits dispatch. adobeFireflyClient.ts 1958->2317 (+upload helpers, extract sources, resolve blob ids). Note: 2317 not 2316 — check-file-size.mjs counts LOC via split(\"\\n\").length (counts the trailing-newline empty element), which is 1 higher than `wc -l` on a file ending in \\n; the PR's original entry (2316) was measured with wc -l and undercounted by 1 against the actual gate.",
|
||||
"_rebaseline_pr1043_minimax_tts": "Upstream port decolua/9router#1043 (toanalien) own growth: audioSpeech.ts 965->1061 (+96). Adds MiniMax T2A v2 TTS dispatch (handleMinimaxSpeech + hexToBytes helper) — provider entry was already in audioRegistry (format: minimax-tts) but no handler existed, falling through to the OpenAI-compatible default that fails (T2A has custom shape + hex-encoded audio + base_resp envelope). New branch sits next to the other inline provider branches (xiaomi-mimo, coqui, tortoise, aws-polly) — extracting would just create indirection. Covered by tests/unit/minimax-tts-1043.test.ts (3 tests, GREEN: success, base_resp error, invalid-hex).",
|
||||
"_rebaseline_pr4592_exclude_exhausted_auto": "Reconcile #4592 already-merged growth: combo.ts 2991->3036 (+45, terminal-status quota-cutoff exclusion in buildAutoCandidates + opt-in gate). Fast-gate PR->release does not run check:file-size.",
|
||||
"open-sse/executors/antigravity.ts": 1986,
|
||||
"open-sse/executors/base.ts": 2132,
|
||||
"open-sse/executors/codex.ts": 2031,
|
||||
"open-sse/executors/cursor.ts": 2032,
|
||||
"open-sse/executors/deepseek-web.ts": 1492,
|
||||
"open-sse/executors/grok-web.ts": 1357,
|
||||
"open-sse/executors/muse-spark-web.ts": 1826,
|
||||
"open-sse/handlers/chatCore.ts": 6579,
|
||||
"open-sse/handlers/imageGeneration.ts": 4031,
|
||||
"open-sse/handlers/responseSanitizer.ts": 1466,
|
||||
"open-sse/handlers/search.ts": 1997,
|
||||
"open-sse/handlers/videoGeneration.ts": 1382,
|
||||
"open-sse/mcp-server/schemas/tools.ts": 2019,
|
||||
"open-sse/mcp-server/server.ts": 1882,
|
||||
"open-sse/mcp-server/tools/advancedTools.ts": 1456,
|
||||
"open-sse/services/accountFallback.ts": 2571,
|
||||
"open-sse/services/adobeFireflyBrowserLogin.ts": 1771,
|
||||
"open-sse/services/adobeFireflyClient.ts": 3899,
|
||||
"open-sse/services/adobeFireflySession.ts": 1304,
|
||||
"open-sse/services/claudeCodeCompatible.ts": 1563,
|
||||
"open-sse/services/combo.ts": 4742,
|
||||
"open-sse/services/compression/strategySelector.ts": 1379,
|
||||
"open-sse/services/compression/engines/ccr/index.ts": 1024,
|
||||
"open-sse/executors/antigravity.ts": 2384,
|
||||
"open-sse/executors/base.ts": 2559,
|
||||
"open-sse/executors/codex.ts": 2438,
|
||||
"open-sse/executors/cursor.ts": 2439,
|
||||
"open-sse/executors/deepseek-web.ts": 1791,
|
||||
"open-sse/executors/grok-web.ts": 1629,
|
||||
"open-sse/executors/muse-spark-web.ts": 2192,
|
||||
"open-sse/handlers/chatCore.ts": 7895,
|
||||
"open-sse/handlers/imageGeneration.ts": 4838,
|
||||
"open-sse/handlers/responseSanitizer.ts": 1760,
|
||||
"open-sse/handlers/search.ts": 2397,
|
||||
"open-sse/handlers/videoGeneration.ts": 1659,
|
||||
"open-sse/mcp-server/schemas/tools.ts": 2423,
|
||||
"open-sse/mcp-server/server.ts": 2259,
|
||||
"open-sse/mcp-server/tools/advancedTools.ts": 1748,
|
||||
"open-sse/services/accountFallback.ts": 3086,
|
||||
"open-sse/services/adobeFireflyBrowserLogin.ts": 2126,
|
||||
"open-sse/services/adobeFireflyClient.ts": 4679,
|
||||
"open-sse/services/adobeFireflySession.ts": 1565,
|
||||
"open-sse/services/claudeCodeCompatible.ts": 1876,
|
||||
"open-sse/services/combo.ts": 5691,
|
||||
"open-sse/services/compression/strategySelector.ts": 1655,
|
||||
"open-sse/services/compression/engines/ccr/index.ts": 1229,
|
||||
"_rebaseline_2026_08_22_11084_ccr_caller_gate": "PR #11084 (HouMinXi) own growth: open-sse/services/compression/engines/ccr/index.ts 1000->1024 (first listing — the engine was unlisted and drifted just over the 1000 cap; +24 are the callerSupportsCcrRetrieve gate that skips replacement entirely for callers without the retrieve tool, closing the stranded-prompt incident measured in production). Covered by tests/unit/compression/ccr-non-mcp-full-prompt-loss-7746.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"open-sse/services/contextManager.ts": 1001,
|
||||
"open-sse/services/contextManager.ts": 1202,
|
||||
"_rebaseline_2026_08_22_11113_purify_system_first": "PR #11113 (ggdayup) own growth: open-sse/services/contextManager.ts 1000->1001 (+1, purifyHistory merges the compression notice into the leading system message instead of splicing a second one mid-array — live-confirmed TokenRouter 400s; the +1 is the merge-into-leading branch, not extractable). Covered by tests/unit/context-manager-purify-system-first.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"open-sse/services/rateLimitManager.ts": 1517,
|
||||
"open-sse/translator/response/openai-responses.ts": 1652,
|
||||
"open-sse/utils/cursorAgentProtobuf.ts": 1956,
|
||||
"open-sse/utils/stream.ts": 3756,
|
||||
"src/app/(dashboard)/dashboard/HomePageClient.tsx": 1804,
|
||||
"src/app/(dashboard)/dashboard/analytics/ComboHealthTab.tsx": 1340,
|
||||
"src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx": 4052,
|
||||
"src/app/(dashboard)/dashboard/cache/media/MediaPageClient.tsx": 1387,
|
||||
"src/app/(dashboard)/dashboard/combos/page.tsx": 6114,
|
||||
"src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx": 1668,
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/PoolWizard.tsx": 1329,
|
||||
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": 3400,
|
||||
"src/app/(dashboard)/dashboard/health/page.tsx": 1514,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx": 1721,
|
||||
"src/app/(dashboard)/dashboard/providers/page.tsx": 2527,
|
||||
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1561,
|
||||
"src/app/(dashboard)/dashboard/settings/components/PricingTab.tsx": 1325,
|
||||
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 1911,
|
||||
"src/app/(dashboard)/dashboard/settings/components/ResilienceTab.tsx": 1460,
|
||||
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 2118,
|
||||
"src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": 2045,
|
||||
"src/app/(dashboard)/dashboard/usage/components/BudgetTab.tsx": 1336,
|
||||
"src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx": 2792,
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": 1455,
|
||||
"src/app/api/providers/[id]/models/route.ts": 3069,
|
||||
"src/app/api/v1/models/catalog.ts": 2076,
|
||||
"src/lib/db/apiKeys.ts": 1988,
|
||||
"src/lib/db/core.ts": 2131,
|
||||
"src/lib/db/migrationRunner.ts": 1431,
|
||||
"src/lib/db/models.ts": 1426,
|
||||
"src/lib/db/providers.ts": 1344,
|
||||
"src/lib/memory/retrieval.ts": 1395,
|
||||
"src/lib/tailscaleTunnel.ts": 1563,
|
||||
"src/lib/usage/providerLimits.ts": 1317,
|
||||
"src/shared/components/OAuthModal.tsx": 1474,
|
||||
"src/shared/components/RequestLoggerV2.tsx": 2118,
|
||||
"src/shared/components/analytics/charts.tsx": 1346,
|
||||
"src/shared/services/cliRuntime.ts": 1459,
|
||||
"src/sse/handlers/chat.ts": 2493,
|
||||
"src/sse/services/auth.ts": 3443,
|
||||
"open-sse/services/rateLimitManager.ts": 1821,
|
||||
"open-sse/translator/response/openai-responses.ts": 1983,
|
||||
"open-sse/utils/cursorAgentProtobuf.ts": 2348,
|
||||
"open-sse/utils/stream.ts": 4508,
|
||||
"src/app/(dashboard)/dashboard/HomePageClient.tsx": 2165,
|
||||
"src/app/(dashboard)/dashboard/analytics/ComboHealthTab.tsx": 1608,
|
||||
"src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx": 4863,
|
||||
"src/app/(dashboard)/dashboard/cache/media/MediaPageClient.tsx": 1665,
|
||||
"src/app/(dashboard)/dashboard/combos/page.tsx": 7337,
|
||||
"src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx": 2002,
|
||||
"src/app/(dashboard)/dashboard/costs/quota-share/components/PoolWizard.tsx": 1595,
|
||||
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": 4080,
|
||||
"src/app/(dashboard)/dashboard/health/page.tsx": 1817,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx": 2066,
|
||||
"src/app/(dashboard)/dashboard/providers/page.tsx": 3033,
|
||||
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1874,
|
||||
"src/app/(dashboard)/dashboard/settings/components/PricingTab.tsx": 1590,
|
||||
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 2294,
|
||||
"src/app/(dashboard)/dashboard/settings/components/ResilienceTab.tsx": 1752,
|
||||
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 2542,
|
||||
"src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": 2454,
|
||||
"src/app/(dashboard)/dashboard/usage/components/BudgetTab.tsx": 1604,
|
||||
"src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx": 3351,
|
||||
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": 1746,
|
||||
"src/app/api/providers/[id]/models/route.ts": 3683,
|
||||
"src/app/api/v1/models/catalog.ts": 2492,
|
||||
"src/lib/db/apiKeys.ts": 2386,
|
||||
"src/lib/db/core.ts": 2558,
|
||||
"src/lib/db/migrationRunner.ts": 1718,
|
||||
"src/lib/db/models.ts": 1712,
|
||||
"src/lib/db/providers.ts": 1613,
|
||||
"src/lib/memory/retrieval.ts": 1674,
|
||||
"src/lib/tailscaleTunnel.ts": 1876,
|
||||
"src/lib/usage/providerLimits.ts": 1581,
|
||||
"src/shared/components/OAuthModal.tsx": 1769,
|
||||
"src/shared/components/RequestLoggerV2.tsx": 2542,
|
||||
"src/shared/components/analytics/charts.tsx": 1616,
|
||||
"src/shared/services/cliRuntime.ts": 1751,
|
||||
"src/sse/handlers/chat.ts": 2992,
|
||||
"src/sse/services/auth.ts": 4132,
|
||||
"_rebaseline_2026_08_28_mergebatch_v3851_provenance_sweep_batch6": "/merge-batch 2026-08-27/28 (v3.8.51) provider/asset provenance & legal compliance sweep — combining the Designer Web + Felo Web + Runtime + GPL-derived (Raycast/Hailuo Web, #11691) retirement guards at their shared chokepoints: src/sse/services/auth.ts 3432->3443 (+11, getProviderCredentials()'s two sequential retirement-check if-blocks plus getModelInfoOrRetirementResponse() catch-branch wiring), src/sse/handlers/chatHelpers.ts 1019->1037 (+18, the combined retirement-error catch branches in the executor dispatch path), src/shared/constants/providers/apikey/gateways.ts 1330->1347 (+17, catalog drift from the same PR chain since the prior 2026-08-11 rebaseline), open-sse/services/autoCombo/virtualFactory.ts 1130->1132 (+2, retirement guard import wiring at the virtual-instance factory chokepoint). Each guard call is irreducible per-mechanism wiring at pre-existing chokepoints (getExecutor, resolveExecutorWithProxy, chat.ts/chatHelpers.ts catch branches, providers.ts write paths) — combining them is additive, not a new branch. Covered by the focused test suites of each boarded PR (chatcore-executor-proxy.test.ts, provider-node-reserved-prefix.test.ts, gpl-derived-provider-removals.test.ts, migration-166-retire-gpl-derived-providers.test.ts, among others).",
|
||||
"_rebaseline_2026_08_24_lasterror_provider_error_detail": "PR (ntdat812) own growth: src/sse/services/auth.ts 3344->3346 (+2). One line is the import of describeUpstreamFailure from @/shared/utils/upstreamError, which replaces the string-only collapse `typeof errorText === \"string\" ? errorText.slice(0, 100) : \"Provider error\"` at the single markAccountUnavailable chokepoint (net 0 lines there) — the logic itself lives in upstreamError.ts, next to the extractErrorMessage it reuses, so nothing else moved into this file. The second line is the repo's own lint-staged prettier pass splitting a pre-existing two-statements-on-one-line at getProviderCredentials (`invalidateManagedLease(...); log.warn(...)`); it re-applies on any commit that touches this file, so it is not separable from the change. Covered by tests/unit/provider-error-detail-lastError.test.ts.",
|
||||
"_rebaseline_2026_08_23_11186_synced_inventory_routing": "PR #11186 (pacocartones) own growth: src/sse/services/auth.ts 3260->3337 (+77, loadAdvertisedModelsForSelfHostedConnections + the modelNotAdvertised candidate-filter predicate — pins chat routing to the connection whose synced inventory actually advertises the model, fixing spurious model-not-found on multi-host self-hosted setups; at the existing credential-selection chokepoint, not extractable without splitting the selection flow). Covered by tests/unit/chat-routing-synced-inventory-11089.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"tests/unit/account-fallback-service.test.ts": 2044,
|
||||
"tests/unit/provider-validation-specialty.test.ts": 3880,
|
||||
"open-sse/executors/hyperagent.ts": 1334,
|
||||
"src/lib/tokenHealthCheck.ts": 1369,
|
||||
"open-sse/executors/default.ts": 1355,
|
||||
"open-sse/executors/kiro.ts": 1390,
|
||||
"open-sse/translator/request/openai-to-kiro.ts": 1374,
|
||||
"open-sse/utils/sseHeartbeat.ts": 194,
|
||||
"open-sse/utils/proxyFetch.ts": 1244,
|
||||
"tests/unit/account-fallback-service.test.ts": 2453,
|
||||
"tests/unit/provider-validation-specialty.test.ts": 4656,
|
||||
"open-sse/executors/hyperagent.ts": 1601,
|
||||
"src/lib/tokenHealthCheck.ts": 1643,
|
||||
"open-sse/executors/default.ts": 1626,
|
||||
"open-sse/executors/kiro.ts": 1668,
|
||||
"open-sse/translator/request/openai-to-kiro.ts": 1649,
|
||||
"open-sse/utils/sseHeartbeat.ts": 233,
|
||||
"open-sse/utils/proxyFetch.ts": 1493,
|
||||
"_rebaseline_2026_08_23_11177_dns_retry_classification": "PR #11177 (rqzbeh) own growth: proxyFetch.ts 1239->1244 (+5, EAI_AGAIN/ENOTFOUND/ETIMEDOUT join the retryable dispatcher classification alongside ECONNREFUSED — bounded socket retries for transient DNS failures, part of the #10443 Hermes→Antigravity stream-drop fixes). Covered by tests/unit/proxy-fetch-dns-retry-10443.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry: DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web (Codex) provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legítima acima do cap; gateways.ts = god-file de catálogo de providers que cresceu com os PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o próprio PR #9421 foi o que quebrou o arquivo; sem split até o release, congelado no tamanho atual). Owner autorizou rebaseline com anotação (2026-08-11).": {
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062,
|
||||
@@ -452,20 +452,20 @@
|
||||
"src/shared/components/ModelSelectModal.tsx": 1138,
|
||||
"src/shared/constants/providers/apikey/gateways.ts": 1250
|
||||
},
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1173,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1408,
|
||||
"_rebaseline_2026_08_23_11207_aws_polly_fields": "PR #11207 (rafacpti23, draft) own growth: AddApiKeyModal.tsx 1082->1173 (+91, AWS SigV4 credential fields for aws-polly — Access Key ID / Region / optional Session Token blocks with providerText i18n labels, at the existing per-provider form-section chokepoint; the file is the known god-modal with repeated dated rebaselines). Covered by tests/unit/dashboard/aws-polly-connection-modal-fields.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"_rebaseline_2026_08_22_11156_enter_check_disabled": "PR #11156 (rqzbeh) own growth: AddApiKeyModal.tsx 1080->1082 (+2, Enter keydown handler now mirrors the isCheckDisabled condition — owner-requested post-merge polish from #11056; the rest of the diff is Prettier reflow). Covered by tests/unit/ui/add-api-key-modal-enter-key.test.tsx (jsdom render test, Enter dispatch assertions).",
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051,
|
||||
"src/shared/components/ModelSelectModal.tsx": 1138,
|
||||
"src/shared/constants/providers/apikey/gateways.ts": 1347,
|
||||
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1387,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1262,
|
||||
"src/shared/components/ModelSelectModal.tsx": 1366,
|
||||
"src/shared/constants/providers/apikey/gateways.ts": 1618,
|
||||
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1665,
|
||||
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry": "DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web (Codex) provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legitima acima do cap; gateways.ts = god-file de catalogo de providers que cresceu com PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o proprio PR #9421 quebrou o arquivo); bridge.ts (PR #8949) = ponte Chromium vendored; proxyFetch.ts 1207->1220 = drift herdado de merges. Owner autorizou rebaseline com anotacao (2026-08-11).",
|
||||
"src/lib/modelCapabilities.ts": 1072,
|
||||
"src/lib/modelCapabilities.ts": 1287,
|
||||
"_rebaseline_2026_08_21_11034_effort_variants": "DRIFT do tip (base-red #9985): modelCapabilities.ts 1016->1072 (+56) acumulado por PRs ja mergeadas no release/v3.8.50 — principalmente #11034 (resolve effort-variant capabilities a partir do modelo base), alem de #10963/#11040/#10987 growth dos catalogos. Tip puro ficou vermelho neste gate; rebaseline no tip por push direto (owner pre-autorizou crescimento legitimo). Nao tocou no arquivo da #11038.",
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts": 1014,
|
||||
"open-sse/config/imageRegistry.ts": 1034,
|
||||
"src/sse/handlers/chatHelpers.ts": 1037,
|
||||
"src/shared/middleware/chatBodyAdmission.ts": 1118,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts": 1217,
|
||||
"open-sse/config/imageRegistry.ts": 1241,
|
||||
"src/sse/handlers/chatHelpers.ts": 1245,
|
||||
"src/shared/middleware/chatBodyAdmission.ts": 1342,
|
||||
"_rebaseline_2026_08_22_11020_sigterm_drain": "PR #11020 (RaviTharuma) own growth: chatBodyAdmission.ts 1005->1009 (+4, heavyweight admission leases now increment the SIGTERM drain counter and releaseChatAdmissionWhenDone holds it for the SSE lifetime — closes #11015; +4 are the lease/drain wiring lines at the existing admission chokepoint). Covered by tests/unit/chat-body-admission.test.ts heavyweight-lease cases. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"_rebaseline_2026_08_20_10668_tabitoken_gateway": "#10668 (yawar-aquil) own catalog growth: src/shared/constants/providers/apikey/gateways.ts 1268->1283 (+15, entirely this PR diff -- one new tabitoken gateway entry, data lines only; base moved from 1255 to 1268 via other merges since the PR forked). Not combination drift: reproducible on the PR branch alone, so the WS5.5 release-captain rule does not apply. Extraction is not available -- the file is pure data (own header: \"Pure data; merged by apikey/index.ts via spread\") and already split into 6 family files under apikey/. Same precedent as _rebaseline_2026_08_14_imagetotext_servicekinds (#10275/#10291, gateways.ts 1250->1255, data lines only) and _rebaseline_2026_08_11_v3850_merge_storm_provider_registry (owner-authorized for this same file).",
|
||||
"_rebaseline_2026_08_20_10878_10799_provider_health_probes": "PRs #10878 (unsupported OpenAI-like validation probes stay neutral) + #10799 (preserve credential health on inconclusive NVIDIA-timeout/Antigravity-400 probes) own growth: src/app/api/providers/[id]/test/route.ts 946->1025 (+79, sum of both boarded together). Both add narrowly-scoped classification branches at the existing test-route dispatch chokepoint (unsupported-capability skip, credential-inconclusive detection) rather than new files, mirroring the prior 2026_06_27_5193 rebaseline of the same file. Covered by tests/unit/provider-validation-unsupported-neutral.test.ts + tests/unit/provider-health-inconclusive-probes.test.ts.",
|
||||
@@ -477,22 +477,25 @@
|
||||
"_rebaseline_2026_08_23_tip_drift_post_batch0823": "Tip drift after the 2026-08-23 merge wave: chatBodyAdmission.ts 1009->1118 (+109, gate count incl. +1) and auth.ts 3337->3344 (+7), both grown by merges already on origin/release/v3.8.50 (verified identical on the pristine tip) — not by the codex-appserver-hardening PR that carries this bump. Owner pre-authorized baseline bumps 2026-08-22.",
|
||||
"_rebaseline_2026_08_24_11355_cooldown_recovery_guards": "PR #11355 own growth: test/route.ts 1215->1237, +22 (startup crash-recovery guard: clearStaleCrashCooldowns() now parses the persisted rate_limited_until deadline and skips clearing rows still genuinely in the future, instead of clearing every non-terminal cooldown unconditionally). Cohesive fix at the existing test-route dispatch chokepoint alongside the #11141 probe builder. Covered by tests/unit/startup-stale-cooldown-recovery.test.ts + tests/unit/repro-zai-cooldown-cleared-by-connection-test.test.ts.",
|
||||
"_rebaseline_2026_08_24_video_bridge_fu02_fu07_sampler": "PRs #11344 (FU-02 one-frame scene-aware determinism) + #11381 (FU-07 opt-in segment_aware structural sampling) own growth: videoBridgeRuntime.ts <1000->1009, +9 (sum of both boarded together in the same merge-batch). #11344 adds the deterministic one-frame midpoint fallback + policyEffective=uniform report at the existing scene_aware seam; #11381 adds the bounded local-only FFmpeg structural pre-analysis pass (scene/freeze/blur/exposure/SI-TI) and its budget-reallocation logic. Covered by tests/unit/guardrails/videoBridgeSampler.test.ts, tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts, tests/integration/video-bridge-sampler-ffmpeg.test.ts. Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive).",
|
||||
"open-sse/services/autoCombo/virtualFactory.ts": 1138,
|
||||
"open-sse/services/autoCombo/virtualFactory.ts": 1374,
|
||||
"_rebaseline_2026_08_29_9133_candidates_inspector_skip_flag": "#9133 own growth: open-sse/services/autoCombo/virtualFactory.ts 1138->1139 (+1, net of extraction). Fix: prepareVirtualAutoComboInputs gained an opt-in `skip` parameter so the read-only #7819 candidate inspector (open-sse/handlers/autoComboCandidates.ts) can build the FULL, unfiltered pool and decorate a resilience-blocked candidate as reachable:false instead of filterResilienceBlockedCandidates silently dropping the row before the inspector ever sees it (routing is unaffected — it never passes `skip`). The connectionsById map-building loop was extracted to buildConnectionResilienceMap() in resilienceCandidateFilter.ts (net 0 there since Prettier still breaks the call over multiple lines) and the now-unused ConnectionResilienceView import was dropped; the sole remaining growth is the new `skip` default parameter itself, which Prettier always places on its own line once the preceding options object parameter already breaks across lines — not further reducible without splitting prepareVirtualAutoComboInputs's signature away from its own body. Covered by tests/unit/auto-combo-candidates-locked-model-visible.test.ts (TDD repro: red before the fix, green after) plus the existing tests/unit/noauth-autocombo-lockout-7623.test.ts and tests/unit/auto-combo-credentialed-model-pool.test.ts (unaffected routing-path behavior).",
|
||||
"_rebaseline_2026_08_29_11481_model_exposure_list": "Feature #11481 (explicit model exposure allow/deny list for /v1/models, mirrored into auto/* combo pools) own growth on top of #9133's +1: open-sse/services/autoCombo/virtualFactory.ts 1139->1145 (measured real line count after both #9133 and #11481 merged together = one import line for filterModelExposureCandidates plus the filter-and-reassign block at the existing buildPreparedPool chokepoint, immediately after the filterPaidOnlyCandidates call it mirrors — the exact pattern #6512 already established for hidePaidModels). The actual predicate (isModelExposureAllowed, glob support via the shared globToRegex matcher) lives in the new src/shared/utils/modelExposureList.ts leaf, and the pool-filter wrapper lives in the new open-sse/services/autoCombo/modelExposureFilter.ts leaf (both well under cap) — this file only carries the minimal call-site wiring plus import, not extractable further without hiding the buildPreparedPool filter chain. Covered by tests/unit/autoCombo/model-exposure-filter-11481.test.ts (pure filter, all branches) and tests/unit/model-exposure-list.test.ts (predicate).",
|
||||
"_rebaseline_2026_08_28_mergebatch_v3851_qwen_retirement": "/merge-batch 2026-08-28 (v3.8.51): #11713 (Qwen Web retirement) own growth: open-sse/services/autoCombo/virtualFactory.ts 1132->1135 (+3, combining the Designer + Runtime retirement-guard filter into the single runtimeConnections predicate at the existing candidate-pool chokepoint, now excluding Qwen Web alongside Felo Web). Irreducible per-mechanism wiring, additive not a new branch. Covered by tests/unit/virtual-auto-combo.test.ts.",
|
||||
"_rebaseline_2026_08_28_mergebatch_v3851_chatgptweb_retirement": "/merge-batch 2026-08-28 (v3.8.51): #11754 (common ChatGPT Web retirement) own growth: open-sse/services/autoCombo/virtualFactory.ts 1135->1138 (+3, an early `available` connection filter for the retired chatgpt-web/cgpt-web ids applied to both the active and disabled-noauth connection lists, ahead of the existing Designer+Runtime runtimeConnections filter). Irreducible per-mechanism wiring, additive not a new branch. Covered by tests/unit/virtual-auto-combo.test.ts.",
|
||||
"src/lib/cloudflaredTunnel.ts": 1078,
|
||||
"src/shared/components/RequestLoggerDetail.tsx": 1018,
|
||||
"src/app/api/providers/[id]/test/route.ts": 1255,
|
||||
"src/lib/guardrails/videoBridgeRuntime.ts": 1009,
|
||||
"src/lib/cloudflaredTunnel.ts": 1294,
|
||||
"src/shared/components/RequestLoggerDetail.tsx": 1334,
|
||||
"_rebaseline_2026_08_30_11703_json_tree_viewer": "/merge-batch 2026-08-30 (v3.8.51): #11703 (hartmark) own growth: src/shared/components/RequestLoggerDetail.tsx 1018->1111 (+93). The 2026-07-22 annotation on this same file said 'no further growth without split rationale' — this PR does split: the collapsible-JSON-tree rendering logic itself lives in the sibling RequestLoggerDetail.sections.tsx (PayloadSection/StreamSection extraction, +82 lines there) plus two new leaves (JsonTreeExpandControls.tsx, useTimestampTitles.ts) and a new store (jsonTreeExpandStore.ts) — all well under cap. The +93 remaining here is the irreducible call-site wiring: import + mount JsonTreeExpandControls, wire the per-section expand-level state and timestamp-tooltip hook into the existing detail panel layout. Covered by the PR's own tests/unit/dashboard/payload-section-collapsible-json.test.tsx, timestamp-titles.test.tsx, tests/unit/shared/json-tree-expand-store.test.ts, short-call-id.test.ts (43/43 vitest + 11/11 native pass).",
|
||||
"src/app/api/providers/[id]/test/route.ts": 1506,
|
||||
"src/lib/guardrails/videoBridgeRuntime.ts": 1211,
|
||||
"_rebaseline_2026_08_28_mergebatch_v3851_ratchet_bank_reconcile": "/merge-batch 2026-08-28 (v3.8.51): boarding #11702 (fix/verify-ratchet-bank object-note comparator) surfaced a large stale `frozen`/`testFrozen` snapshot on PR #11702's own branch (forked before the 08-11 banking outage — see the object-valued `_rebaseline_2026_08_11_v3850_merge_storm_provider_registry` note above, the exact bug #11702 fixes in the verifier) — its conflicting block duplicated ~85 already-tracked files with sizes smaller than the current release tip, and still listed open-sse/executors/chatgpt-web.ts (deleted by the #11754 retirement). Resolved by re-measuring every file in the union of both sides directly on the boarded tree (split(\"\\n\").length, matching check-file-size.mjs) rather than trusting either stale snapshot; dropped the dead chatgpt-web.ts entry; kept the two genuinely-new entries PR #11702's branch had that this tip did not yet track (src/app/api/providers/[id]/test/route.ts, src/lib/guardrails/videoBridgeRuntime.ts, both re-measured). Same reconciliation applied to the testFrozen block above.",
|
||||
"open-sse/executors/chatgpt-web.ts": 4213,
|
||||
"open-sse/executors/chatgpt-web.ts": 5056,
|
||||
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry: DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legítima acima do cap; gateways.ts = god-file de catálogo de providers que cresceu com os PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o próprio PR #9421 foi o que quebrou o arquivo; sem split até o release, congelado no tamanho atual). Owner autorizou rebaseline com anotação (2026-08-11).": {
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062,
|
||||
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051,
|
||||
"src/shared/components/ModelSelectModal.tsx": 1138,
|
||||
"src/shared/constants/providers/apikey/gateways.ts": 1250
|
||||
},
|
||||
"open-sse/executors/commandCode.ts": 1059
|
||||
"open-sse/executors/commandCode.ts": 1271
|
||||
},
|
||||
"_rebaseline_base_2026_08_10_proxyfetch": "Base-red fix (green-prs sweep, issue #9985): open-sse/utils/proxyFetch.ts 1207 > cap 1000 — new proxied-TLS fetch helper introduced by the Fal reference-image work. Owner-authorized quick rebaseline to green; structural slim tracked for v3.9.0.",
|
||||
"_rebaseline_2026_07_27_v3849_train2": "Merge-train 2 (7 PRs) — owner-approved 2026-07-27. Single entry: chatCore.ts 4955->5006 (#8595, Responses multi-turn image compaction before the context hard-reject). Genuine irreducible growth at the existing compaction chokepoint in handleChatCore — the PR adds a last-resort retry against the concrete budget plus the estimateFinalInputTokens helper, both wired at the pre-existing call site rather than a new branch. Covered by tests/unit/8560-responses-image-compaction.test.ts (4 tests).",
|
||||
@@ -665,5 +668,7 @@
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch2": "/merge-batch 2026-08-26 (v3.8.51) batch 2: three legitimate growths. #11083 src/shared/components/RequestLoggerDetail.tsx new-file cap, lands at 1018 (+18 over 1000) — copy-all button for request detail modal. #11631 src/shared/constants/providers/apikey/gateways.ts 1321->1330 (1min.ai gateway entry). #11628 src/sse/services/auth.ts 3376->3432 (credential-health isolation from model failures). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch5": "/merge-batch 2026-08-26 (v3.8.51) batch 5: #11642 tests/integration/skills-pipeline.test.ts new regression test for the configured-provider-over-fallback search selection (#11524), lands at 1010 lines (+10 over the 1000 new-file testCap). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
|
||||
"_rebaseline_2026_06_30_v3842_release_chatgptweb_compression": "v3.8.42 cycle-close file-size reconciliation (DRIFT measured OK on each PR's base, stacked above frozen at the merge tip; fast-path PR->release/** does not run check:file-size). (1) open-sse/executors/chatgpt-web.ts 2870->3206 (+336 = #5531 portable SHA3-512 sentinel-PoW wiring with the native-vs-fallback digest path + #5536 GPT-5.5 Pro handoff branch; the pure Keccak-f[1600] fallback itself already lives in the separate leaf open-sse/utils/sha3-512.ts — the executor growth is the cohesive call-site/handoff logic, not extractable without hiding the sentinel chokepoint). (2) tests/unit/chatgpt-web.test.ts 2855->3159 (+304 = #5536 GPT-5.5 Pro handoff coverage; pair-file with its executor). (3) open-sse/services/compression/strategySelector.ts 997->1022 (+25 = #5527 T02 honest default-on pipeline inflation guard wiring at the existing finalizeStackedResult choke). All cohesive at existing chokepoints; covered by tests/unit/chatgpt-web-sha3-boringssl-5531.test.ts, chatgpt-web.test.ts (GPT-5.5 Pro), compression-pipeline-inflation-guard.test.ts.",
|
||||
"open-sse/executors/chatgpt-web.ts": "3241"
|
||||
"open-sse/executors/chatgpt-web.ts": "3241",
|
||||
"_rebaseline_2026_08_30_11771_vercel_gateway_passthrough": "PR #11771 adds passthroughModels: true (1 line) to the Vercel AI Gateway registry entry — no split available, single-line provider-config addition.",
|
||||
"_relax_velocity_2026_08_30": "127 frozen line caps and cap/testCap raised by 20% (velocity phase; see quality-baseline.json _policy)."
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"src/lib/guardrails/videoBridgeHelpers.ts": {
|
||||
"TS2488": 1,
|
||||
"TS2365": 2,
|
||||
"TS2322": 1,
|
||||
"TS2345": 1
|
||||
}
|
||||
"TS2488": 2,
|
||||
"TS2365": 3,
|
||||
"TS2322": 2,
|
||||
"TS2345": 2
|
||||
},
|
||||
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (5 → 9); velocity phase, see quality-baseline.json _policy."
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"_comment": "Catraca de qualidade. 'down' = nao pode aumentar; 'up' = nao pode cair. Atualize via 'npm run quality:ratchet -- --update' (somente quando melhora). Cada valor e um numero REAL medido, nunca um chute. Cobertura entra na Fase 4 a partir de um run de cobertura mergeada no CI.",
|
||||
"metrics": {
|
||||
"eslintWarnings": {
|
||||
"value": 0,
|
||||
"value": 1050,
|
||||
"direction": "down",
|
||||
"_rebaseline_2026_08_05_post_prune": "Apertado 5000->0 em 2026-08-05: o gate mede via lint:json COM as suppressions aplicadas (config/quality/eslint-suppressions.json congela a divida da migracao TS7), entao a contagem real do gate e 0. O 5000 anterior foi medido SEM suppressions (4139 brutos) e fazia o require-tighten reprovar todo PR de codigo (delta 5000>slack). Divida TS7 continua rastreada nas suppressions; warning NOVO (fora delas) agora e red imediato, que e a politica."
|
||||
},
|
||||
@@ -12,77 +12,77 @@
|
||||
"eps": 0
|
||||
},
|
||||
"coverage.statements": {
|
||||
"value": 80.8,
|
||||
"value": 67.33,
|
||||
"direction": "up",
|
||||
"tightenSlack": 5
|
||||
},
|
||||
"coverage.lines": {
|
||||
"value": 80.8,
|
||||
"value": 67.33,
|
||||
"direction": "up",
|
||||
"tightenSlack": 5
|
||||
},
|
||||
"coverage.functions": {
|
||||
"value": 86.42,
|
||||
"value": 72.02,
|
||||
"direction": "up",
|
||||
"tightenSlack": 5,
|
||||
"_rebaseline_2026_07_17_combo_recovery_hints": "86.44 -> 86.42 (-0.02). PR #7625: adds failureTracker.ts with new functions (+2 function definitions). Coverage denominator grew by 2 functions; numerator unchanged (the 8 coverage shards do not exercise failureTracker.ts). Legitimate drift from feature addition, not regression. Tighten via --require-tighten next cycle."
|
||||
},
|
||||
"coverage.branches": {
|
||||
"value": 78.1,
|
||||
"value": 65.08,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 5
|
||||
},
|
||||
"coverage.chatCore.lines": {
|
||||
"value": 72.45,
|
||||
"value": 60.38,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.combo.lines": {
|
||||
"value": 85.42,
|
||||
"value": 71.18,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.accountFallback.lines": {
|
||||
"value": 96.78,
|
||||
"value": 80.65,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.auth.lines": {
|
||||
"value": 92.55,
|
||||
"value": 77.13,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.routeGuard.lines": {
|
||||
"value": 98.73,
|
||||
"value": 82.28,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.error.lines": {
|
||||
"value": 92.13,
|
||||
"value": 76.78,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.publicCreds.lines": {
|
||||
"value": 99.07,
|
||||
"value": 82.56,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"coverage.circuitBreaker.lines": {
|
||||
"value": 95.09,
|
||||
"value": 79.24,
|
||||
"direction": "up",
|
||||
"eps": 1.5,
|
||||
"tightenSlack": 10
|
||||
},
|
||||
"openapiCoverage.pct": {
|
||||
"value": 39,
|
||||
"value": 32.5,
|
||||
"direction": "up",
|
||||
"eps": 0.5,
|
||||
"_tighten_2026_08_28_v3851_eslint_refreeze": "38.4 -> 39. Aperto EXIGIDO pelo step --require-tighten do job No new ESLint warnings na PR #11955 (release/v3.8.51): assim que o ESLint voltou a medir 0/0, o ratchet passou a cobrar o aperto. 39 = valor medido pelo collect-metrics do CI no run 33213844112 e reproduzido numa sala limpa da ponta 777d9d1629 (clone --depth 1 + npm ci do lockfile). A cobertura melhorou porque as rotas novas do ciclo entraram documentadas em docs/openapi.yaml; nenhuma rota tocada nesta PR. Aperto = gate mais ESTRITO, nunca mascaramento.",
|
||||
@@ -94,7 +94,7 @@
|
||||
"_rebaseline_2026_07_13_v3847_release": "39.3 -> 38.0 (-1.3, beyond the 0.5 eps). v3.8.47 cycle drift: the cycle merged ~45 PRs adding API routes (relay repair/free-pool #6909, backpressure #6590, combo context requirements #6907, services/usage endpoints) faster than openapi.yaml documentation; same class as the v3.8.34/v3.8.39 rebaselines. Documented follow-up: raise coverage next cycle via docs/openapi.yaml additions."
|
||||
},
|
||||
"i18nUiCoverage.pct": {
|
||||
"value": 100,
|
||||
"value": 83.33,
|
||||
"direction": "up",
|
||||
"eps": 0.5,
|
||||
"_tighten_2026_08_08_modality_bridge": "99 -> 100. Tighten required by the PR quality gate after the Modality Bridge UI keys were translated across all 42 non-English locales. CI collect-metrics on PR #9782 measured i18nUiCoverage.pct=100 with 0 ESLint warnings and 0 ESLint errors; locale dry-sync and UI coverage also report 100% with no missing keys or placeholders.",
|
||||
@@ -104,7 +104,7 @@
|
||||
"_rebaseline_2026_07_28_v3849_release": "75.5 -> 99 (+23.5). Aperto EXIGIDO pelo modo --require-tighten do ratchet: a métrica melhorou de verdade no ciclo v3.8.49. A causa é o workflow assíncrono de tradução, que finalmente alcançou o denominador em EN — as rebaselines anteriores (v3.8.39/.44/.47) foram todas afrouxamentos registrando o atraso das traduções, e agora ele foi pago. O coletor SUBTRAI os placeholders (present - placeholder em scripts/quality/collect-metrics.mjs), então os 317 marcadores __MISSING__ que esta release introduziu para o drift de valor já estão descontados dos 99 — o número é honesto, não inflado por placeholder. Medido pelo collect-metrics do CI no run 30404226939."
|
||||
},
|
||||
"deadExports": {
|
||||
"value": 416,
|
||||
"value": 500,
|
||||
"direction": "down",
|
||||
"_rebaseline_2026_08_19_v3850_basereds_9985": "415 -> 416. Measured on release/v3.8.50 tip 14a480453 during the #9985 base-red drain. Removed the 2 genuinely-dead symbols traced to a specific recent change (PR #10148, 2026-08-18): the unused src/lib/quota/providerCapabilities.ts file and the unused ProviderQuotaMonitor interface in providerQuotaTelemetry.ts (418 -> 416). The remaining +1 could not be attributed to a single recent commit after checking every dead-list entry touched since the 2026-08-14 baseline measurement (most are pre-existing debt on files edited for unrelated reasons); rebaselining the residual 1 rather than guessing at removals. Structural cleanup stays tracked in #3501.",
|
||||
"_rebaseline_2026_08_09_v3850_post_sweep": "227 -> 230. Measured by npm run check:dead-code on the unmodified release/v3.8.50 tip 382449d593 during the mandatory --full-ci pre-flight. The +3 is inherited cycle drift from the authorized merge sweep; this repair adds no production exports. Rebaseline records the actual tip so ci.yml quality-gate can run, while structural cleanup remains separate debt.",
|
||||
@@ -119,7 +119,7 @@
|
||||
"_rebaseline_2026_08_20_pr_10798": "415 -> 418. Inherited cycle drift from parallel merges into release/v3.8.50 since the 2026-08-14 OCR-series rebaseline (3 more dead exports surfaced by knip 6.32). This PR (#10798, omniroute-plugin log-level fix) adds 0 production exports: it touches @omniroute/opencode-plugin (separate workspace, not scanned), changelog.d/, and scripts/check/check-env-doc-sync.mjs (array entries, not exports). The +3 is NOT from this PR; rebaselined so the gate runs while structural cleanup of the newly-surfaced dead exports remains separate debt."
|
||||
},
|
||||
"cognitiveComplexity": {
|
||||
"value": 1223,
|
||||
"value": 1437,
|
||||
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "951->957 (+6). Same cycle-drift + own-growth split as the complexity-baseline.json note dated 2026-07-25 (PR #8523, Dario embedded service): cognitive-complexity does not run on PR->release fast-gates, so drift accrues unratcheted. Base upstream/release/v3.8.49 tip measures 956 locally with this PR's commits removed; this branch measures 957 both locally and on the CI runner. This PR's own genuine contribution is +1: the new mode-selector conditional rendering (Native/CLIProxyAPI/Dario/Fallback branches plus the fallback-backend picker) in ConnectionRow.tsx. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25_8470_hyperagent_sticky_thread": "951->957 (+6). PR #8470 (artickc, fix/hyperagent-tool-loop-thread-sticky) pre-green validation. Trust-but-verify: origin/release/v3.8.49 tip alone (pristine, no PR changes) already measures 956 with node scripts/check/check-cognitive-complexity.mjs — i.e. +5 is inherited cycle drift unrelated to this PR (cognitive-complexity does not run on PR->release fast-gates). This PR's OWN growth adds exactly +1: per-file eslint scoped scan (eslint --config eslint.complexity-ratchets.config.mjs open-sse/executors/hyperagent.ts) on base vs PR shows extractMessageText() crossing the threshold for the first time (new sonarjs/cognitive-complexity violation, 26 > 15) from the new Anthropic tool_use/tool_result flattening branches; resolveHyperAgentThreadBinding's existing pre-#8470 violation (16) grows to 21 (still counted once) from the new root-key lookup tier; createHyperAgentThread and execute() are unchanged pre-existing violations. Net repo-wide total = 956 (inherited drift) + 1 (this PR's own new violation) = 957. Full-repo re-measurement of the merged branch was attempted but not completed live due to heavy concurrent devbox load (many other /green-prs sessions running the identical full-repo eslint scan in parallel); the value here is derived from two independently-clean measurements (base-tip full scan + per-file base-vs-PR delta) rather than a third full-repo run. Covered by tests/unit/executor-hyperagent.test.ts (19/19). Tighten via --update next cycle.",
|
||||
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 956->968 (+12). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 968 on the combined boarded tree (tip ac15014ca7) vs 956 on the pristine release tip. The batch's new over-threshold functions come from the pre-screen-flagged complexity-growth set (#8378/#8432/#8476/#8526 etc); each PR is under-ceiling alone, the combined batch adds +12. Same merge-burst class as the notes below; owner chose ceiling-absorb over per-PR extraction. Structural shrink tracked in #3501; tighten via --update next cycle.",
|
||||
@@ -150,13 +150,13 @@
|
||||
"_note_8266": "2026-07-23: +1 own-growth from #8266 (@backryun) Alibaba media provider dispatch wiring"
|
||||
},
|
||||
"typeCoveragePct": {
|
||||
"value": 92.17,
|
||||
"value": 76.81,
|
||||
"direction": "up",
|
||||
"eps": 0.05,
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"codeqlAlerts": {
|
||||
"value": 9,
|
||||
"value": 11,
|
||||
"direction": "down",
|
||||
"dedicatedGate": true,
|
||||
"_rebaseline_2026_08_06_base_grew": "Base branch file-size drift: translator-openai-to-gemini.test.ts grew 1619->1622 (test assertions for Gemini translator compatibility). CodeQL alert (js/insufficient-password-hash in raycast.ts) is pre-existing base-red; incremented baseline to match.",
|
||||
@@ -170,7 +170,7 @@
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"zizmorFindings": {
|
||||
"value": 194,
|
||||
"value": 233,
|
||||
"_rebaseline_2026_08_20_radar_export_workflow": "190 -> 192 (+2). Workflow novo `.github/workflows/radar-export.yml` (passo 10 do go-live do Radar: publica o export estável do catálogo como asset de release para o servidor privado baixar via RADAR_EXPORT_URL). Os +2 são unpinned-uses @vN: actions/checkout@v7 + actions/setup-node@v7 — a MESMA convenção deliberada de todos os workflows (ver _scanner_harden_workflows_2026_06_16); fixar por SHA só este violaria a convenção. O findings artipacked do checkout foi CORRIGIDO com `persist-credentials: false` (o job publica via GH_TOKEN em `gh release`, não usa a credencial do checkout). Nenhuma classe nova de template-injection / cache-poisoning / dangerous-triggers. Medido local com zizmor 1.25.2 via `node scripts/check/check-workflows.mjs --ratchet` = 191; +1 do delta conhecido do runner (ver _rebaseline_2026_07_28_ci_runner_delta: o runner enxerga 1 unpinned-uses @vN a mais que o devbox no mesmo commit; a baseline segue o runner) => 192.",
|
||||
"_rebaseline_2026_07_20_aliasresolver_hook_split_7808": "175 -> 176 (+1). Companion to PR #7808 (CodeQL js/incomplete-url-substring-sanitization fix in bin/aliasResolver.mjs). The +1 is NOT caused by this PR's code changes (bin/* is not a workflow file) — it is a pre-existing drift that surfaced because the ratchet gate runs on this PR's CI: the zizmor scanner version on the GitHub runner gained a new rule (or extended an existing one) since the v3.8.49 baseline was seeded on 2026-07-17. Breakdown: the new finding is an unpinned-uses @vN class item on one of the existing workflows (same deliberate convention as _scanner_harden_workflows_2026_06_16 — @vN is intentional, SHA-pinning only this one would violate the convention). No new template-injection/artipacked/cache-poisoning/dangerous-triggers classes introduced. Measured by the Quality Gates (Extended) job on run 29713001401 = 176, baseline was 175. Note: by the time this landed on release/v3.8.49, the baseline was already at 176 via _rebaseline_2026_07_17_combo_recovery_hints — this entry is kept as historical record; no further bump applied.",
|
||||
"_rebaseline_2026_07_17_v3849_release": "169 -> 175 (+6). Cycle workflow drift (v3.8.48/v3.8.49): npm-publish.yml (new, WS1.3 #7092), electron-release.yml, nightly-compat.yml, nightly-release-green.yml, CI restructures (#7501 full-history base fetch, #7355 main-green, #7202 merge-queue gates, Trunk/Codecov). Breakdown vs v3.8.47: +3 unpinned-uses (@vN convention, deliberate per _scanner_harden_workflows_2026_06_16), +2 cache-poisoning (artifact upload/cache in the OWN electron-release/npm-publish RELEASE workflows -- operator-controlled, not fork-PR exploitable), +1 excessive-permissions (nightly-compat.yml permissions:issues). No new template-injection/artipacked/dangerous-triggers. Measured with zizmor 1.25.2 via `node scripts/check/check-workflows.mjs --ratchet` = 175 on da3a0be69.",
|
||||
@@ -185,12 +185,12 @@
|
||||
"_rebaseline_2026_08_28_npm_publish_hosted_stage_job": "192 -> 194 (+2). Job novo `stage-npm` em .github/workflows/npm-publish.yml: o npm RECUSA `--provenance` vindo de runner self-hosted (422 \"Unsupported GitHub Actions runner environment\"), e o job `publish` nao pode migrar para runner hospedado porque 16 GB nao bastam para o fallback next-build do build:cli (documentado no proprio runs-on). A separacao foi a unica saida que preserva a atestacao SLSA que a 3.8.49 ja tem. Os +2 sao da MESMA convencao deliberada de todos os workflows (ver _scanner_harden_workflows_2026_06_16): unpinned-uses @vN em actions/download-artifact@v8 + actions/setup-node@v7, mais o cache-poisoning que o proprio setup-node@v7 ja gera nos outros 2 jobs deste MESMO arquivo (linhas 85 e 463) e que ja esta na baseline. Fixar por SHA so este job violaria a convencao. Nenhuma classe nova: zero template-injection / artipacked / dangerous-triggers / excessive-permissions — o job declara apenas contents:read + id-token:write, que e o minimo para a proveniencia. Medido pelo job Quality Gates (Extended) no run 33162... da PR #11877 = 194."
|
||||
},
|
||||
"vulnCount": {
|
||||
"value": 22,
|
||||
"value": 27,
|
||||
"direction": "down",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"bundleSize": {
|
||||
"value": 8653,
|
||||
"value": 10384,
|
||||
"direction": "down",
|
||||
"dedicatedGate": true,
|
||||
"_rebaseline_2026_07_07_v3846_release_close": "5601->6534 (+933). v3.8.46 release close: gzip of the 4 bin/*.mjs entrypoints (size-limit + @size-limit/file) grew from this cycle's feature/fix merges pulled transitively into the CLI entrypoints (new providers, combo pipeline strategy #6396, effort/thinking standardization #6241, catalog cache-invalidation #6408). Measured 6534 locally via `check:bundle-size --ratchet` (deterministic gzip, matches CI). Legitimate cycle growth; shrink is separate debt.",
|
||||
@@ -202,169 +202,169 @@
|
||||
"_rebaseline_2026_08_25_v3850_release_preflight": "8045 -> 8461 (+416 gzip bytes, +5.2%). Release v3.8.50 pre-flight, measured with the real size-limit + @size-limit/file path on tip e3e188e993 (the 08-09 rebaseline was taken on e0ce95c592 and the branch kept moving). The growth is concentrated in the two entrypoints the cycle actually touched: omniroute.mjs 4380->4700 and nodeRuntimeSupport.mjs 887->983 — #11039 (native Bun backend + Dockerfile.bun), #10870 (report .env lines that never take effect) and #10101 (strip inline comments when parsing .env values). mcp-server.mjs (1195) and reset-password.mjs (1583) are unchanged. Every entry stays far below its absolute budget (4700/15000, 1195/5000, 983/8000, 1583/6000). Legitimate cycle growth; shrinking is separate debt. The direction:down ratchet stays blocking from this measured tip."
|
||||
},
|
||||
"openapiBreaking": {
|
||||
"value": 4,
|
||||
"value": 5,
|
||||
"direction": "down",
|
||||
"dedicatedGate": true,
|
||||
"_note": "oasdiff breaking-change gate (Fase 9 Onda 0). Blocks any breaking change vs base spec.",
|
||||
"_rebaseline_2026_08_22_combo_create_min1": "0 -> 4, split 3 own + 1 inherited. Docs-only alignment of components.schemas.ComboCreate with the request contract already enforced by the API since 638fc5fbd (combo create refuses an empty model list) and d5034ea52: `model`/`nodes` were phantom properties the server never accepted, and `models` (array, minItems 1) is the real required field. OWN findings (3, caused by this commit): removed `model`, removed `nodes`, added required `models` on POST /api/combos — spec-vs-server drift, not client-facing breakage, no working client could have relied on the removed shapes. INHERITED finding (1, NOT caused by this PR's code changes — pre-existing drift already present at parent d5034ea52): PATCH /api/combos/{id} request-body-added-required; that route's patch operation declares its own inline requestBody (required: true, bare object schema, docs/openapi.yaml ~2107-2118) and does not reference ComboCreate, so this finding exists independently of the ComboCreate alignment (same own-growth vs inherited-drift convention as _rebaseline_2026_07_20_aliasresolver_hook_split_7808). No code change in this PR; follow-up tracking = this change's PR description."
|
||||
},
|
||||
"mutationScore.src/sse/services/auth.ts": {
|
||||
"value": 52.57,
|
||||
"value": 43.81,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/accountFallback.ts": {
|
||||
"value": 68.38,
|
||||
"value": 56.98,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.src/server/authz/routeGuard.ts": {
|
||||
"value": 76.08,
|
||||
"value": 63.4,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.src/shared/utils/circuitBreaker.ts": {
|
||||
"value": 56.94,
|
||||
"value": 47.45,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/utils/error.ts": {
|
||||
"value": 43.83,
|
||||
"value": 36.53,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/utils/publicCreds.ts": {
|
||||
"value": 59.76,
|
||||
"value": 49.8,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/autoStrategy.ts": {
|
||||
"value": 41.33,
|
||||
"value": 34.44,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/comboStructure.ts": {
|
||||
"value": 57.82,
|
||||
"value": 48.18,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/validateQuality.ts": {
|
||||
"value": 61.33,
|
||||
"value": 51.11,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/comboPredicates.ts": {
|
||||
"value": 56.62,
|
||||
"value": 47.18,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/rrState.ts": {
|
||||
"value": 70.88,
|
||||
"value": 59.07,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/shadowRouting.ts": {
|
||||
"value": 48,
|
||||
"value": 40,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/targetSorters.ts": {
|
||||
"value": 68.3,
|
||||
"value": 56.92,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/comboData.ts": {
|
||||
"value": 76.94,
|
||||
"value": 64.12,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/quotaScoring.ts": {
|
||||
"value": 39.73,
|
||||
"value": 33.11,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/services/combo/quotaStrategies.ts": {
|
||||
"value": 50.3,
|
||||
"value": 41.92,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/passthroughHelpers.ts": {
|
||||
"value": 80.89,
|
||||
"value": 67.41,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/sanitization.ts": {
|
||||
"value": 70.15,
|
||||
"value": 58.46,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/upstreamTimeouts.ts": {
|
||||
"value": 33,
|
||||
"value": 27.5,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/comboContextCache.ts": {
|
||||
"value": 13.62,
|
||||
"value": 11.35,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/idempotency.ts": {
|
||||
"value": 42.82,
|
||||
"value": 35.68,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/responseHeaders.ts": {
|
||||
"value": 62.7,
|
||||
"value": 52.25,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/executorHelpers.ts": {
|
||||
"value": 70.39,
|
||||
"value": 58.66,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/memoryExtraction.ts": {
|
||||
"value": 62.06,
|
||||
"value": 51.72,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/nonStreamingSse.ts": {
|
||||
"value": 72.82,
|
||||
"value": 60.68,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/passthroughToolNames.ts": {
|
||||
"value": 66.42,
|
||||
"value": 55.35,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/headers.ts": {
|
||||
"value": 94.29,
|
||||
"value": 78.58,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/logTruncation.ts": {
|
||||
"value": 77.64,
|
||||
"value": 64.7,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/memorySkillsInjection.ts": {
|
||||
"value": 13.49,
|
||||
"value": 11.24,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/semanticCache.ts": {
|
||||
"value": 60.16,
|
||||
"value": 50.13,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"mutationScore.open-sse/handlers/chatCore/telemetryHelpers.ts": {
|
||||
"value": 83.18,
|
||||
"value": 69.32,
|
||||
"direction": "up",
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"rtlPhysicalClasses": {
|
||||
"value": 1011,
|
||||
"value": 1214,
|
||||
"direction": "down",
|
||||
"eps": 0,
|
||||
"_seeded_2026_07_28": "Measured by scripts/check/check-rtl-ratchet.mjs. tests/unit/ui/rtl-logical-classes.test.tsx pins four components and states it is partial (#3541); this bounds the remainder."
|
||||
@@ -407,5 +407,15 @@
|
||||
"_zizmor_rebaseline_2026_06_20_ci_build_artifact_reuse": "zizmorFindings 148 -> 152. Drift legitimo deste PR ao reutilizar o artefato next-build do job Build em package-artifact/electron-package-smoke e ao separar o build de compatibilidade Node 26: +4 unpinned-uses novos (2x actions/download-artifact@v8, actions/checkout@v7, actions/setup-node@v6). Mantida a convencao deliberada @vN dos workflows (sem SHA-pinning/manual update burden), conforme precedentes _scanner_harden_workflows_2026_06_16 e _zizmor_rebaseline_2026_06_19_*. Sem novos findings de template-injection/artipacked/cache-poisoning; medido localmente com zizmor 1.25.2 via `npm run check:workflows -- --ratchet` = 152.",
|
||||
"_cognitive_rebaseline_2026_07_27_3850_relax_v2_20pct": "cognitiveComplexity 971->1223 (+252, +26.0% over pristine 971). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +48 on 2026-07-27; v2 = v1 +20% buffer = +58 → +252 total (cycle 971 measured pristine → 1223 ceiling). Justification: same as complexity v2 — the v3.8.50 release cut coincides with high-merge activity; owner accepted enlarging the headroom to cover the entire PREPARE phase (5 minor cycles .50-.54) without per-PR rebaseline noise, given that re-tightening is mechanical at v3.8.51 via the combo.ts/chatCore.ts decomposition work scheduled in .51/.52 (ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 1009 (shrink of 214 from structural extraction during the decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 1009 floor still gives 38 units of post-tighten headroom vs the current pristine 971. Tracked via same roadmap issue as complexity v2. Window: v3.8.50 (release cut) → v3.8.54 close (RE-TIGHTEN at v3.8.51 prep merge per ROADMAP.md). Last entry unless measured regression. v1 entry retained below for audit trail.",
|
||||
"_cognitive_rebaseline_2026_07_27_3850_relax": "cognitiveComplexity 971->1019 (+48). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +48 covers Train 1D (+15) + headroom for 3.8.50/.51 batches. RE-TIGHTENING MANDATORY in v3.8.51: target 1009 (from combo.ts/chatCore.ts decomposition scheduled in .51/.52 per ROADMAP.md phases). Tracked via same roadmap issue as complexity. SUPERSEDED by _cognitive_rebaseline_2026_07_27_3850_relax_v2_20pct (v1 +20% buffer) — retained for audit. Last entry unless measured regression.",
|
||||
"_vuln_rebaseline_2026_08_04_9439_cve_drift": "vulnCount 10->22 (HIGH=10, MODERATE=12, measured by osv-scanner v2.3.8 in PR #9439's own CI run). This is CVE variance, not a dependency change made by this PR: `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty — neither file was touched anywhere in this branch's history. The osv-scanner vulnerability ratchet apparently does not run on every commit landed directly to release/v3.8.50 (same 'fast-gate PR->release skips this check' pattern already documented for check:file-size, e.g. _rebaseline_2026_07_01_v3843_release_5609), so newly-disclosed CVEs in already-present transitive dependencies accumulated on the release branch and only surfaced here because this PR's rebase onto the current release/v3.8.50 tip pulled them in. This exact scenario — 'a newly-disclosed CVE in an already-present dep can trip the gate with no dependency change on your part' — is the documented expected behavior in _osv_flip_blocking_2026_06_16_v3827 above, whose prescribed remedy is 'bump the dep, or re-baseline vulnCount with justification+issue' (docs/security/SUPPLY_CHAIN.md -> 'Variância de CVE'). osv-scanner is not available in this sandbox to enumerate the exact GHSA/CVE ids and safely bump only the affected transitive deps without a broader, separately-scoped dependency-audit pass; re-baselining here unblocks this PR without masking anything introduced by it. Tracked for follow-up: a dedicated dependency-bump PR should re-tighten vulnCount back down once the specific advisories are enumerated locally with osv-scanner installed."
|
||||
"_vuln_rebaseline_2026_08_04_9439_cve_drift": "vulnCount 10->22 (HIGH=10, MODERATE=12, measured by osv-scanner v2.3.8 in PR #9439's own CI run). This is CVE variance, not a dependency change made by this PR: `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty — neither file was touched anywhere in this branch's history. The osv-scanner vulnerability ratchet apparently does not run on every commit landed directly to release/v3.8.50 (same 'fast-gate PR->release skips this check' pattern already documented for check:file-size, e.g. _rebaseline_2026_07_01_v3843_release_5609), so newly-disclosed CVEs in already-present transitive dependencies accumulated on the release branch and only surfaced here because this PR's rebase onto the current release/v3.8.50 tip pulled them in. This exact scenario — 'a newly-disclosed CVE in an already-present dep can trip the gate with no dependency change on your part' — is the documented expected behavior in _osv_flip_blocking_2026_06_16_v3827 above, whose prescribed remedy is 'bump the dep, or re-baseline vulnCount with justification+issue' (docs/security/SUPPLY_CHAIN.md -> 'Variância de CVE'). osv-scanner is not available in this sandbox to enumerate the exact GHSA/CVE ids and safely bump only the affected transitive deps without a broader, separately-scoped dependency-audit pass; re-baselining here unblocks this PR without masking anything introduced by it. Tracked for follow-up: a dedicated dependency-bump PR should re-tighten vulnCount back down once the specific advisories are enumerated locally with osv-scanner installed.",
|
||||
"_policy": {
|
||||
"phase": "velocity",
|
||||
"since": "2026-08-30",
|
||||
"until": "4.0.0",
|
||||
"relaxPct": 20,
|
||||
"requireTighten": false,
|
||||
"monitor": "scripts/quality/baseline-headroom.mjs (nightly-release-green → baseline-headroom job)",
|
||||
"note": "Owner decision 2026-08-30: speed matters more than debt until the v4.0 LTS modularization. Every numeric baseline was loosened by relaxPct in one pass (see _relax_* note). check-quality-ratchet skips --require-tighten while this block exists; headroom is monitored nightly. At 4.0 the phase closes: re-measure on the pure tip, tighten, delete this block."
|
||||
},
|
||||
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): eslintWarnings 0 → 1050; coverage.statements 80.8 → 67.33; coverage.lines 80.8 → 67.33; coverage.functions 86.42 → 72.02; coverage.branches 78.1 → 65.08; coverage.chatCore.lines 72.45 → 60.38; coverage.combo.lines 85.42 → 71.18; coverage.accountFallback.lines 96.78 → 80.65; coverage.auth.lines 92.55 → 77.13; coverage.routeGuard.lines 98.73 → 82.28; coverage.error.lines 92.13 → 76.78; coverage.publicCreds.lines 99.07 → 82.56; coverage.circuitBreaker.lines 95.09 → 79.24; openapiCoverage.pct 39 → 32.5; i18nUiCoverage.pct 100 → 83.33; deadExports 416 → 500; cognitiveComplexity 1197 → 1437; typeCoveragePct 92.17 → 76.81; codeqlAlerts 9 → 11; zizmorFindings 194 → 233; vulnCount 22 → 27; bundleSize 8653 → 10384; openapiBreaking 4 → 5; mutationScore.src/sse/services/auth.ts 52.57 → 43.81; mutationScore.open-sse/services/accountFallback.ts 68.38 → 56.98; mutationScore.src/server/authz/routeGuard.ts 76.08 → 63.4; mutationScore.src/shared/utils/circuitBreaker.ts 56.94 → 47.45; mutationScore.open-sse/utils/error.ts 43.83 → 36.53; mutationScore.open-sse/utils/publicCreds.ts 59.76 → 49.8; mutationScore.open-sse/services/combo/autoStrategy.ts 41.33 → 34.44; mutationScore.open-sse/services/combo/comboStructure.ts 57.82 → 48.18; mutationScore.open-sse/services/combo/validateQuality.ts 61.33 → 51.11; mutationScore.open-sse/services/combo/comboPredicates.ts 56.62 → 47.18; mutationScore.open-sse/services/combo/rrState.ts 70.88 → 59.07; mutationScore.open-sse/services/combo/shadowRouting.ts 48 → 40; mutationScore.open-sse/services/combo/targetSorters.ts 68.3 → 56.92; mutationScore.open-sse/services/combo/comboData.ts 76.94 → 64.12; mutationScore.open-sse/services/combo/quotaScoring.ts 39.73 → 33.11; mutationScore.open-sse/services/combo/quotaStrategies.ts 50.3 → 41.92; mutationScore.open-sse/handlers/chatCore/passthroughHelpers.ts 80.89 → 67.41; mutationScore.open-sse/handlers/chatCore/sanitization.ts 70.15 → 58.46; mutationScore.open-sse/handlers/chatCore/upstreamTimeouts.ts 33 → 27.5; mutationScore.open-sse/handlers/chatCore/comboContextCache.ts 13.62 → 11.35; mutationScore.open-sse/handlers/chatCore/idempotency.ts 42.82 → 35.68; mutationScore.open-sse/handlers/chatCore/responseHeaders.ts 62.7 → 52.25; mutationScore.open-sse/handlers/chatCore/executorHelpers.ts 70.39 → 58.66; mutationScore.open-sse/handlers/chatCore/memoryExtraction.ts 62.06 → 51.72; mutationScore.open-sse/handlers/chatCore/nonStreamingSse.ts 72.82 → 60.68; mutationScore.open-sse/handlers/chatCore/passthroughToolNames.ts 66.42 → 55.35; mutationScore.open-sse/handlers/chatCore/headers.ts 94.29 → 78.58; mutationScore.open-sse/handlers/chatCore/logTruncation.ts 77.64 → 64.7; mutationScore.open-sse/handlers/chatCore/memorySkillsInjection.ts 13.49 → 11.24; mutationScore.open-sse/handlers/chatCore/semanticCache.ts 60.16 → 50.13; mutationScore.open-sse/handlers/chatCore/telemetryHelpers.ts 83.18 → 69.32; rtlPhysicalClasses 1011 → 1214"
|
||||
}
|
||||
|
||||
44
config/release/wreq-js-native-manifest.json
Normal file
44
config/release/wreq-js-native-manifest.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"package": "wreq-js",
|
||||
"version": "3.0.0",
|
||||
"source": "https://registry.npmjs.org/wreq-js/-/wreq-js-3.0.0.tgz",
|
||||
"npmIntegrity": "sha512-RZCoRSevVPpH4A4B4MxbFGo/pVPFveWd2gbe4ENKpPWlKXEYklZSDESOjBMmrIsmnkHh+nhM4PNJvG+NL7wBPA==",
|
||||
"license": "MIT",
|
||||
"nativeAddons": [
|
||||
{
|
||||
"path": "rust/wreq-js.darwin-arm64.node",
|
||||
"size": 7690880,
|
||||
"sha256": "c82eec39df691adb94f2cd09a8ff51335de8587cf132cd8b3ec797469a4b5002"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.darwin-x64.node",
|
||||
"size": 8192028,
|
||||
"sha256": "073b8a8a4c26aedbce7c14eef3e5567918e62e8dbf4d28296b23f9d2beec2981"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.linux-arm64-gnu.node",
|
||||
"size": 8520824,
|
||||
"sha256": "861d96a78caf7ce02c9ae8d37f1c59f5b0480e3142775c32917fcfe9b88524b0"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.linux-arm64-musl.node",
|
||||
"size": 8735472,
|
||||
"sha256": "2409a3578c8c440df419b4d5abe3ac149bec48881611a6dc1571b95e6246552d"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.linux-x64-gnu.node",
|
||||
"size": 9048992,
|
||||
"sha256": "55b40f4602c52111dfcdcc93db83f9d0de55d0ef7540348757709d58d05a9b64"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.linux-x64-musl.node",
|
||||
"size": 8974880,
|
||||
"sha256": "bd52d15b1bb4704b11561a8aa95648a6c91150082b5af0e39dd1608b7db2d317"
|
||||
},
|
||||
{
|
||||
"path": "rust/wreq-js.win32-x64-msvc.node",
|
||||
"size": 7967232,
|
||||
"sha256": "7451a8701b82c946b03ba2be2f15257260a250b9e0ed9910611b22564fbec7a9"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -514,7 +514,7 @@ For the full stealth playbook and operational guidance, see
|
||||
Primary state DB (SQLite):
|
||||
|
||||
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
|
||||
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
|
||||
- DB access: import specific `src/lib/db/*` modules directly (the old `localDb.ts` barrel was removed)
|
||||
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
|
||||
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
|
||||
|
||||
@@ -888,7 +888,7 @@ flowchart LR
|
||||
### Persistence
|
||||
|
||||
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
|
||||
- `src/lib/localDb.ts`: compatibility re-export for DB modules
|
||||
- `src/lib/db/*`: import specific modules directly — no barrel (the old `localDb.ts` re-export layer was removed)
|
||||
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
|
||||
|
||||
## Provider Executor Coverage (Strategy Pattern)
|
||||
|
||||
@@ -313,7 +313,7 @@ table groups the actual directories and notable top-level files.
|
||||
|
||||
Top-level files in `src/lib/`:
|
||||
|
||||
- `localDb.ts` — re-export layer only. **Never** add logic here.
|
||||
- The old `localDb.ts` barrel was removed — consumers import specific `src/lib/db/*` modules directly.
|
||||
- `proxyHealth.ts`, `proxyLogger.ts`, `tokenHealthCheck.ts`, `localHealthCheck.ts`
|
||||
- `oneproxyRotator.ts`, `oneproxySync.ts`
|
||||
- `apiBridgeServer.ts`, `cacheLayer.ts`, `semanticCache.ts`, `settingsCache.ts`
|
||||
@@ -759,7 +759,7 @@ See [RESILIENCE_GUIDE.md](./RESILIENCE_GUIDE.md) and the dedicated section in
|
||||
2. Export CRUD functions for your domain.
|
||||
3. If new tables: add a migration under `src/lib/db/migrations/`, numbered
|
||||
sequentially, idempotent, transactional.
|
||||
4. Re-export from `src/lib/localDb.ts` (re-export only — **no logic**).
|
||||
4. Importers use direct imports from `@/lib/db/yourModule` (no barrel — the old `localDb.ts` re-export layer was removed).
|
||||
5. Add tests under `tests/unit/`.
|
||||
|
||||
### Add a new MCP tool
|
||||
@@ -790,7 +790,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
|
||||
- **TypeScript**: `strict: false` (legacy posture). Prefer explicit types over
|
||||
inference for cross-module boundaries.
|
||||
- **Database**: never write raw SQL in routes or handlers — always go through
|
||||
`src/lib/db/` modules. Never add logic to `src/lib/localDb.ts`.
|
||||
`src/lib/db/` modules. Never barrel-import — use specific `src/lib/db/*` modules directly.
|
||||
- **DB-entity typing (#3512)**: a function that writes or reads a DB table's
|
||||
row shape should take/return a named TS interface mirroring that table's
|
||||
columns 1:1, not `any` or an inline anonymous type at the call site. Land
|
||||
@@ -824,7 +824,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
|
||||
## 12. Hard Rules (from CLAUDE.md)
|
||||
|
||||
1. Never commit secrets or credentials.
|
||||
2. Never add logic to `src/lib/localDb.ts`.
|
||||
2. Never barrel-import — use specific `src/lib/db/*` modules directly.
|
||||
3. Never use `eval()` / `new Function()` / implied eval.
|
||||
4. Never commit directly to `main`.
|
||||
5. Never write raw SQL in routes — always go through `src/lib/db/` modules.
|
||||
|
||||
@@ -224,6 +224,55 @@ These run on a cron schedule (and `workflow_dispatch`), never on PRs. All are ad
|
||||
|
||||
---
|
||||
|
||||
## Velocity phase (2026-08-30 → v4.0 LTS): every baseline loosened by 20%
|
||||
|
||||
Owner decision (2026-08-30): until the v4.0 modularization, shipping speed matters more
|
||||
than holding the debt line. Every **numeric** ratchet baseline was loosened by 20% in one
|
||||
auditable pass, and the phase is declared in `config/quality/quality-baseline.json`:
|
||||
|
||||
```json
|
||||
"_policy": { "phase": "velocity", "since": "2026-08-30", "until": "4.0.0",
|
||||
"relaxPct": 20, "requireTighten": false }
|
||||
```
|
||||
|
||||
| What changed | Where |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `metrics.*.value` — lower-is-better counts ×1.2, higher-is-better percentages ÷1.2 (coverage floor 60 kept, `eslintErrors` stays 0, `eslintWarnings` 0 → 20% of the frozen suppression count) | `quality-baseline.json` (`_relax_velocity_2026_08_30` note lists every before → after) |
|
||||
| `count` ×1.2 / `percentage` ×1.2 | `complexity-baseline.json`, `duplication-baseline.json` |
|
||||
| `cap`, `testCap`, every `frozen[*]` / `testFrozen[*]` line cap ×1.2 | `file-size-baseline.json` |
|
||||
| per-file / per-TS-code counts ×1.2 | `api-typecheck-baseline.json`, `dashboard-typecheck-baseline.json`, `open-sse-typecheck-baseline.json` |
|
||||
| `THRESHOLD` 36 → 30 | `scripts/check/check-openapi-coverage.mjs` |
|
||||
| `--require-tighten` becomes advisory while `_policy.requireTighten === false` | `scripts/quality/check-quality-ratchet.mjs` |
|
||||
| nightly `bank-ratchet-shrinks` pauses (it would bank the measured shrink and undo the headroom) | `.github/workflows/nightly-release-green.yml` |
|
||||
|
||||
Allowlists (`eslint-suppressions.json`, `test-masking-allowlist.json`, `test-discovery-baseline.json`,
|
||||
…) are **not** budgets and were not touched. Pass/fail policy gates (secrets, SQL rules,
|
||||
docs/env contract, i18n parity, unit tests) are unchanged — a red test is still a red test.
|
||||
|
||||
**Tooling**
|
||||
|
||||
- `npm run quality:relax-baselines -- --pct 20 --note velocity_YYYY_MM_DD [--dry-run]` — the
|
||||
one-shot relaxation (`scripts/quality/relax-baselines.mjs`); refuses to run twice with the
|
||||
same note.
|
||||
- `npm run quality:headroom [-- --only deadExports,fileSize] [--json out.json --md out.md]` —
|
||||
measures every numeric gate the way CI does and prints the remaining headroom per gate
|
||||
(`scripts/quality/baseline-headroom.mjs`). The nightly `baseline-headroom` job posts the
|
||||
table to the living issue **📈 Baseline headroom (velocity phase)** and adds the
|
||||
`headroom-alert` label when any gate is within 10% of its cap or already over it. That issue
|
||||
is the early warning: a budget that fills in days means the relaxation is being consumed by
|
||||
a few PRs, not by the whole team — look at the offending gate's `_rebaseline_*` notes.
|
||||
|
||||
**Closing the phase at v4.0 (LTS = tighter than before, not "back to normal")**
|
||||
|
||||
1. On the pure `release/v4.0.0` tip: `npm run quality:headroom --json` for the record, then
|
||||
`npm run quality:ratchet -- --update`, `check:file-size --update`,
|
||||
`check:complexity-ratchets --update`, `check:dead-code --update`, each typecheck gate's
|
||||
`--update` — every baseline drops to the measured value.
|
||||
2. Delete `_policy` from `quality-baseline.json` (re-arms `--require-tighten` and the nightly
|
||||
banking), restore `THRESHOLD = 36` (or higher) in `check-openapi-coverage.mjs`.
|
||||
3. Tighten beyond measured where the modularization paid off: file-size `cap` back to 1000
|
||||
(or 800), coverage floors +5, dead exports 0 for the modularized packages.
|
||||
|
||||
## Ratchet Baseline (`quality-baseline.json`)
|
||||
|
||||
The ratchet engine (`scripts/quality/check-quality-ratchet.mjs`) reads `quality-baseline.json`
|
||||
|
||||
221
docs/frameworks/LOG-EXPORT.md
Normal file
221
docs/frameworks/LOG-EXPORT.md
Normal file
@@ -0,0 +1,221 @@
|
||||
---
|
||||
title: "Log Export"
|
||||
version: 3.8.51
|
||||
lastUpdated: 2026-08-29
|
||||
---
|
||||
|
||||
# Log export
|
||||
|
||||
Continuous, incremental export of OmniRoute call logs to an external analytics store.
|
||||
|
||||
The Logs dashboard tab keeps request history in SQLite (`call_logs`), which is bounded by
|
||||
rotation and retention. Log export ships the same record set out on a schedule so it can outlive
|
||||
the local database and be joined against other data. BigQuery is the first destination; the
|
||||
pipeline is a registry, so more destinations are additive.
|
||||
|
||||
---
|
||||
|
||||
## 1. How it works
|
||||
|
||||
```
|
||||
call_logs (SQLite)
|
||||
→ callLogExportSource.getCallLogsForExport(cursor, batchSize)
|
||||
→ LogExportRecord[] (the Logs-tab field set)
|
||||
→ destination client.send(batch)
|
||||
→ advanceLogExportCursor(id, lastRowId, count)
|
||||
```
|
||||
|
||||
- **Schedule** — one `JobRegistry` cron job, `log_export`, defaulting to `0 * * * *` (hourly,
|
||||
UTC). Registered in `src/lib/initCloudSync.ts`; overridable with `OMNIROUTE_LOG_EXPORT_CRON`.
|
||||
Each tick drains every **enabled** destination, sequentially.
|
||||
- **Cursor** — SQLite's implicit `call_logs.rowid`, persisted per destination in
|
||||
`log_export_destinations.cursor_row_id`. `timestamp` is deliberately not the cursor: callers
|
||||
may supply their own value, so a slow request can be written after a faster one that started
|
||||
later, and a timestamp cursor would skip it.
|
||||
- **Batching** — `batch_size` rows per request (default 500), `max_rows_per_run` rows per run
|
||||
(default 10000) so a large backlog drains over several ticks instead of blocking one.
|
||||
- **Delivery** — the cursor advances only after `send()` resolves. A failed batch leaves the
|
||||
cursor where it was, so the same rows are retried on the next run. The guarantee is
|
||||
at-least-once plus destination-side de-duplication, not true exactly-once: BigQuery keys each
|
||||
row by the call-log id, which it honours on a best-effort basis within its own dedup window.
|
||||
- **Overlap guard** — the cron tick and `POST .../run` can fire together. A destination
|
||||
already draining is skipped rather than drained twice (`skipped: true` in the run result),
|
||||
so a concurrent run cannot re-send a batch or write the cursor backwards.
|
||||
- **Purge recovery** — if `cursor_row_id` ends up above `MAX(rowid)` (the whole table was
|
||||
purged and rowids restarted), the runner rewinds to 0 rather than going permanently blind.
|
||||
|
||||
### Payloads (prompts and completions)
|
||||
|
||||
By default the export carries only the summary fields the Logs **list** shows. Turning on
|
||||
**Export prompts and responses** (`includeBodies`) additionally ships what the Logs **detail**
|
||||
pane shows for each call:
|
||||
|
||||
| Field | What it holds |
|
||||
| -------------------------------- | -------------------------------------------------- |
|
||||
| `request_body` / `response_body` | The call payloads as the dashboard renders them |
|
||||
| `pipeline_route_decision` | Which target and model the router picked |
|
||||
| `pipeline_client_request` | The raw request exactly as the client sent it |
|
||||
| `pipeline_openai_request` | After translation into the internal OpenAI shape |
|
||||
| `pipeline_provider_request` | As actually sent upstream, in the provider dialect |
|
||||
| `pipeline_provider_response` | The raw upstream response |
|
||||
| `pipeline_client_response` | What was handed back to the caller |
|
||||
| `pipeline_error` | Pipeline-level error detail for a failed call |
|
||||
| `bodies_truncated` | True when any field above hit `maxBodyBytes` |
|
||||
|
||||
This is prompt content, so it is **off by default** and deliberately a per-destination choice.
|
||||
What ships is what the dashboard shows, because both read through `getCallLogById`: payloads are
|
||||
already PII-sanitised and secret-redacted when they are written, and a call made with a
|
||||
`noLog` API key stores no payload at all, so there is nothing to export.
|
||||
|
||||
Payloads are read per row from the filesystem artifact, so hydration only runs for destinations
|
||||
that asked for it. A row whose artifact is missing or corrupt exports its summary with null
|
||||
payloads rather than failing the batch and stranding the cursor.
|
||||
|
||||
`maxBodyBytes` (default 262144) caps each field. Longer payloads are **truncated rather than
|
||||
dropped** — a clipped prompt still answers "what was asked" — and the row is flagged with
|
||||
`bodies_truncated`. Streamed chunk-by-chunk deltas are not exported; the assembled response is
|
||||
already in `pipeline_provider_response` and `pipeline_client_response`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Files
|
||||
|
||||
| Piece | Location |
|
||||
| -------------------- | -------------------------------------------- |
|
||||
| Destination contract | `src/lib/logExport/types.ts` |
|
||||
| Registry | `src/lib/logExport/registry.ts` |
|
||||
| Secret handling | `src/lib/logExport/secrets.ts` |
|
||||
| Runner (cursor loop) | `src/lib/logExport/runner.ts` |
|
||||
| API projection | `src/lib/logExport/presenter.ts` |
|
||||
| BigQuery destination | `src/lib/logExport/destinations/bigquery.ts` |
|
||||
| Google SA auth | `src/lib/logExport/googleServiceAccount.ts` |
|
||||
| Call-log source | `src/lib/usage/callLogExportSource.ts` |
|
||||
| Persistence | `src/lib/db/logExportDestinations.ts` |
|
||||
| Cron job | `src/lib/jobs/logExportJob.ts` |
|
||||
| REST layer | `src/app/api/log-export/` |
|
||||
| Dashboard page | `src/app/(dashboard)/dashboard/log-export/` |
|
||||
|
||||
Schema: `src/lib/db/migrations/170_log_export_destinations.sql`.
|
||||
|
||||
---
|
||||
|
||||
## 3. REST API
|
||||
|
||||
All routes are management-authenticated (`requireManagementAuth`). Secrets are never returned:
|
||||
a stored secret comes back as the literal `__stored__`, and sending that value back on an update
|
||||
keeps the stored credential.
|
||||
|
||||
Creating or updating a destination whose type declares a secret **requires
|
||||
`STORAGE_ENCRYPTION_KEY`**. Without it `encrypt()` is a silent passthrough, so the write is
|
||||
refused with a 400 rather than putting a credential into SQLite in plaintext (the same guard the
|
||||
Telegram webhook applies).
|
||||
|
||||
| Method | Path | Purpose |
|
||||
| -------- | ---------------------------------------- | ------------------------------------------- |
|
||||
| `GET` | `/api/log-export/types` | Destination types + their config field list |
|
||||
| `GET` | `/api/log-export/destinations` | List destinations (secrets redacted) |
|
||||
| `POST` | `/api/log-export/destinations` | Create a destination |
|
||||
| `GET` | `/api/log-export/destinations/{id}` | Read one |
|
||||
| `PUT` | `/api/log-export/destinations/{id}` | Update name / enabled / config / batching |
|
||||
| `DELETE` | `/api/log-export/destinations/{id}` | Delete |
|
||||
| `POST` | `/api/log-export/destinations/{id}/test` | Probe credentials, write nothing |
|
||||
| `POST` | `/api/log-export/destinations/{id}/run` | Drain now, same path as the scheduled run |
|
||||
| `GET` | `/api/log-export/status` | Cron state, recent runs, backlog per target |
|
||||
|
||||
`GET /api/log-export/types` is what makes the UI generic: the dashboard form is rendered from
|
||||
the returned field descriptors, so a new destination needs no UI change.
|
||||
|
||||
---
|
||||
|
||||
## 4. BigQuery destination
|
||||
|
||||
Config keys (`type: "bigquery"`):
|
||||
|
||||
| Key | Notes |
|
||||
| -------------------- | ----------------------------------------------------------------- |
|
||||
| `projectId` | GCP project holding the dataset |
|
||||
| `datasetId` | `[A-Za-z0-9_]+` |
|
||||
| `tableId` | `[A-Za-z0-9_]+` |
|
||||
| `location` | Only used when the dataset has to be created (default `EU`) |
|
||||
| `serviceAccountJson` | Service-account key. Secret: encrypted at rest, never returned |
|
||||
| `autoCreate` | Create the dataset and table on the first export (default `true`) |
|
||||
|
||||
The service account needs `bigquery.tables.updateData` on the target table, plus
|
||||
`bigquery.datasets.create` / `bigquery.tables.create` when `autoCreate` is on.
|
||||
|
||||
A configured batch is a **cursor** unit, not an HTTP one: `send()` chunks it into insertAll
|
||||
calls of at most 500 rows, so a large `batch_size` cannot trip BigQuery's 10 MB request cap.
|
||||
Transient statuses (408/429/500/502/503/504) are retried up to three times with exponential
|
||||
backoff, reusing the same insertIds; auth and schema failures throw on the first attempt rather
|
||||
than burning the run.
|
||||
|
||||
A table created moments ago is not yet visible to the streaming endpoint, which answers
|
||||
404 for a few seconds. That 404 is retried, but **only when this run created the table** —
|
||||
a genuinely missing table still fails fast. Note that re-creating a table under a name that
|
||||
was recently deleted makes BigQuery refuse streaming inserts for several minutes; that is a
|
||||
property of delete-then-recreate, so prefer a new table name over dropping and re-adding one.
|
||||
|
||||
**A partial failure arrives as HTTP 200 with a non-empty `insertErrors[]`.** That is treated as
|
||||
a failure and throws, which is what stops the cursor from advancing past rows BigQuery never
|
||||
accepted; `tests/unit/log-export-bigquery.test.ts` pins the behaviour.
|
||||
|
||||
Transport is plain REST — a self-signed RS256 assertion is exchanged for an access token at
|
||||
`https://oauth2.googleapis.com/token`, then rows go to `tabledata.insertAll`. No Google SDK is
|
||||
pulled in. Access tokens are cached in-process per (service account, scope).
|
||||
|
||||
The created table carries one column per Logs-tab field plus `exported_at`, and is laid out for
|
||||
how call logs are actually queried:
|
||||
|
||||
- **Day-partitioned on `timestamp`**, so a query bounded by date only scans those days.
|
||||
- **Clustered by `api_key_name`, `provider`, `model`, `status`** (in that order), so filtering by
|
||||
who ran it, where it went, or whether it failed prunes blocks inside each partition. BigQuery
|
||||
allows at most four clustering columns and the order matters: a filter on `api_key_name` alone
|
||||
prunes, a filter on `status` alone does not.
|
||||
- **Optional partition retention** via `partitionExpirationDays` (0 keeps everything), applied
|
||||
when the table is created.
|
||||
|
||||
Both settings apply at creation time. An existing table keeps whatever layout it already has, so
|
||||
point the destination at a new table id if you want to adopt them.
|
||||
|
||||
`tests/unit/log-export-bigquery.test.ts` asserts the mapper and the table schema stay in
|
||||
lockstep, so a new call-log column cannot be silently dropped on the way out.
|
||||
|
||||
Batches are chunked by **both** row count and serialised bytes. Row count alone is not enough
|
||||
once payloads are exported: 500 rows carrying prompts can be tens of megabytes, and insertAll
|
||||
rejects a request over 10 MB. Chunks close at 500 rows or 9 MB, whichever comes first.
|
||||
|
||||
---
|
||||
|
||||
## 5. Adding a destination
|
||||
|
||||
1. Create `src/lib/logExport/destinations/<name>.ts` exporting a `LogExportDestinationType`:
|
||||
a Zod `configSchema`, a `fields` descriptor array for the UI, `secretFields`, and a
|
||||
`createClient(config)` returning `test()` / `prepare()` / `send(records)`.
|
||||
2. Add it to the `DESTINATIONS` array in `src/lib/logExport/registry.ts`.
|
||||
3. Write tests under `tests/unit/`.
|
||||
|
||||
That is the whole change: persistence, the cron job, the REST layer, secret encryption and the
|
||||
dashboard form all read the registry.
|
||||
|
||||
Two rules for a new destination:
|
||||
|
||||
- `send()` **must throw** on a partial failure. Resolving means "the destination has these rows",
|
||||
and the cursor moves past them permanently.
|
||||
- A destination that takes a user-supplied URL must validate it through
|
||||
`parseAndValidateWebhookUrl` (`src/shared/network/outboundUrlGuardPolicy.ts`) before fetching,
|
||||
the same way webhooks do. BigQuery does not need this: its hosts are constants.
|
||||
|
||||
---
|
||||
|
||||
## 6. Operating it
|
||||
|
||||
- **Dashboard**: Integrations → Log export. Add a destination, run **Test** to check credentials
|
||||
without writing rows, then enable it.
|
||||
- **Backlog**: each destination card shows pending rows and the cursor; `GET
|
||||
/api/log-export/status` returns the same figures plus the last 20 job runs.
|
||||
- **A failing destination does not fail the others** — the run summary records per-destination
|
||||
status in `last_status` / `last_error`, and the job run history keeps the aggregate.
|
||||
- **Deleting a destination deletes its cursor.** Re-adding it starts from the oldest retained
|
||||
call log, which re-sends rows the destination may already hold. On BigQuery the per-row
|
||||
`insertId` absorbs that only inside BigQuery's own de-duplication window, so prefer disabling
|
||||
a destination over deleting it.
|
||||
@@ -97,6 +97,12 @@ Plugins are discovered from:
|
||||
1. `~/.omniroute/plugins/<name>/` — user-local installs
|
||||
2. `OMNIROUTE_PLUGIN_PATH` env var — custom directory
|
||||
|
||||
Both are **CLI-only**. The server-side plugin runtime (the marketplace/`plugin.json`
|
||||
plugins that run inside the proxy) has its own scanner with its own override,
|
||||
`OMNIROUTE_PLUGINS_DIR` — see
|
||||
[PLUGIN_MARKETPLACE.md → Plugin directory](./PLUGIN_MARKETPLACE.md#plugin-directory).
|
||||
Setting one does not affect the other.
|
||||
|
||||
Loading errors are caught and printed as warnings — a broken plugin never crashes the CLI.
|
||||
|
||||
## Security
|
||||
|
||||
@@ -161,10 +161,28 @@ Plugins live under the OmniRoute data directory:
|
||||
└─ index.js # (or whatever manifest.main points to)
|
||||
```
|
||||
|
||||
`getDefaultPluginDir()` (`src/lib/plugins/scanner.ts`) resolves this to
|
||||
`<home>/.omniroute/plugins`, where `<home>` is taken from the `HOME` /
|
||||
`USERPROFILE` environment variables. `POST /api/plugins/scan` discovers any
|
||||
subdirectory there that holds a valid `plugin.json` and registers it.
|
||||
`getDefaultPluginDir()` (`src/lib/plugins/scanner.ts`) resolves that directory in
|
||||
three steps:
|
||||
|
||||
1. **`OMNIROUTE_PLUGINS_DIR`**, when set — used verbatim, whatever `HOME` says. This is
|
||||
the explicit knob for Docker/K8s, where the plugin tree is bind-mounted at a path
|
||||
that usually has nothing to do with the container's home directory (#11827).
|
||||
2. `<home>/.omniroute/plugins`, where `<home>` comes from the `HOME` / `USERPROFILE`
|
||||
environment variables.
|
||||
3. `/tmp/.omniroute/plugins`, when the process exports no home at all.
|
||||
|
||||
The resolved directory is logged once at startup as `scanner.dir_resolved`, naming the
|
||||
input that won (`OMNIROUTE_PLUGINS_DIR`, `home`, or `no-home-fallback`) — so an image
|
||||
that silently lands on step 3 says so, instead of only reporting an empty plugin list.
|
||||
`POST /api/plugins/scan` discovers any subdirectory there that holds a valid
|
||||
`plugin.json` and registers it; the same directory is the root that
|
||||
`pluginManager.install()` copies plugins into, so an override moves discovery and
|
||||
installation together.
|
||||
|
||||
> **`OMNIROUTE_PLUGINS_DIR` is not `OMNIROUTE_PLUGIN_PATH`.** The latter is read only by
|
||||
> the CLI command-plugin loader (`bin/cli/plugins.mjs`) to find `omniroute-cmd-*` npm
|
||||
> packages that add `omniroute` subcommands — it has no effect on the runtime scanner
|
||||
> described here. See [PLUGINS.md](./PLUGINS.md) for that side.
|
||||
|
||||
### Custom marketplace registry URL
|
||||
|
||||
|
||||
@@ -60,23 +60,24 @@ Every command honours the **active context** (set with `omniroute connect`, see
|
||||
with `--remote` (or an active remote context) it fetches the catalog from that
|
||||
server and writes the config locally.
|
||||
|
||||
| Command | Tool | What it writes | Key flags | Local vs remote |
|
||||
| -------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
|
||||
| `omniroute setup-codex` | OpenAI Codex CLI | `~/.codex/<name>.config.toml` — one profile per compatible text model (`codex --profile <name>`) | `--remote` `--api-key` `--only` `--dry-run` `--port` `--codex-home` | Both |
|
||||
| `omniroute setup-claude` | Claude Code | `~/.claude/profiles/<name>/settings.json` — one profile per matched model (`CLAUDE_CONFIG_DIR`) | `--remote` `--api-key` `--only` `--dry-run` `--port` `--claude-home` | Both |
|
||||
| `omniroute setup-opencode` | OpenCode (openai-compatible) | `~/.config/opencode/opencode.json` — `omniroute` provider with every catalog model (`opencode -m omniroute/<model>`) | `--remote` `--api-key` `--only` `--model` `--dry-run` `--port` | Both |
|
||||
| `omniroute setup-cline` | Cline | `~/.cline/data/{globalState,secrets}.json` (CLI mode) + prints VS Code extension settings | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--cline-dir` | Both |
|
||||
| `omniroute setup-kilo` | Kilo Code | `~/.local/share/kilo/auth.json` (CLI) + merges `kilocode.*` into VS Code `settings.json` if present | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--auth-path` `--vscode-settings` | Both |
|
||||
| `omniroute setup-continue` | Continue / `cn` CLI | `~/.continue/config.yaml` — `provider: openai` models, key via `${{ secrets.OMNIROUTE_API_KEY }}` | `--remote` `--api-key` `--only` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-cursor` | Cursor | Nothing — prints the in-app steps (Cursor config is opaque SQLite) | `--remote` `--api-key` `--only` `--port` | Both |
|
||||
| `omniroute setup-roo` | Roo Code | `~/.omniroute/roo-settings.json` (import doc) + sets `roo-cline.autoImportSettingsPath` if a VS Code `settings.json` exists | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--import-path` `--vscode-settings` | Both |
|
||||
| `omniroute setup-crush` | Crush | `~/.config/crush/crush.json` — `openai-compat` provider, key via `$OMNIROUTE_API_KEY` | `--remote` `--api-key` `--only` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-goose` | Goose | `~/.config/goose/config.yaml` (`GOOSE_PROVIDER`/`OPENAI_HOST`/`GOOSE_MODEL`) + prints env recipe | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-aider` | Aider | `~/.aider.conf.yml` (`openai-api-base` + `model: openai/<id>`) + prints env recipe | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-qwen` | Qwen Code | `~/.qwen/settings.json` — V4 `modelProviders.openai` array + `OMNIROUTE_API_KEY` in `~/.qwen/.env` | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` `--env-path` | Both |
|
||||
| `omniroute run <target>` | Runtime launch (generic) | Nothing — spawn `claude`/`codex`/`aider`/`goose`/`opencode`/`qwen`/`gemini` with the right env and args; Qwen and Gemini use a temporary isolated home | `--remote` `--base-url` `--context` `--provider` `--model` `--api-key` `--api-key-env` `--dry-run` `--json` `--port` `--profile` `--token` | Both |
|
||||
| `omniroute launch` | Claude Code | Nothing — spawns `claude` with `ANTHROPIC_BASE_URL`/`ANTHROPIC_AUTH_TOKEN` injected | `--remote` `--api-key` `--token` `--profile` `--port` | Both |
|
||||
| `omniroute launch-codex` | OpenAI Codex CLI | Nothing — spawns `codex` with the `omniroute` provider injected via `-c` flags | `--remote` `--api-key` `--profile` (`-p`) `--port` | Both |
|
||||
| Command | Tool | What it writes | Key flags | Local vs remote |
|
||||
| -------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
|
||||
| `omniroute setup-codex` | OpenAI Codex CLI | `~/.codex/<name>.config.toml` — one profile per compatible text model (`codex --profile <name>`) | `--remote` `--api-key` `--only` `--dry-run` `--port` `--codex-home` | Both |
|
||||
| `omniroute setup-claude` | Claude Code | `~/.claude/profiles/<name>/settings.json` — one profile per matched model (`CLAUDE_CONFIG_DIR`) | `--remote` `--api-key` `--only` `--dry-run` `--port` `--claude-home` | Both |
|
||||
| `omniroute setup-opencode` | OpenCode (openai-compatible) | `~/.config/opencode/opencode.json` — `omniroute` provider with every catalog model (`opencode -m omniroute/<model>`) | `--remote` `--api-key` `--only` `--model` `--dry-run` `--port` | Both |
|
||||
| `omniroute setup-cline` | Cline | `~/.cline/data/{globalState,secrets}.json` (CLI mode) + prints VS Code extension settings | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--cline-dir` | Both |
|
||||
| `omniroute setup-kilo` | Kilo Code | `~/.local/share/kilo/auth.json` (CLI) + merges `kilocode.*` into VS Code `settings.json` if present | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--auth-path` `--vscode-settings` | Both |
|
||||
| `omniroute setup-continue` | Continue / `cn` CLI | `~/.continue/config.yaml` — `provider: openai` models, key via `${{ secrets.OMNIROUTE_API_KEY }}` | `--remote` `--api-key` `--only` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-cursor` | Cursor | Nothing — prints the in-app steps (Cursor config is opaque SQLite) | `--remote` `--api-key` `--only` `--port` | Both |
|
||||
| `omniroute setup-roo` | Roo Code | `~/.omniroute/roo-settings.json` (import doc) + sets `roo-cline.autoImportSettingsPath` if a VS Code `settings.json` exists | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--import-path` `--vscode-settings` | Both |
|
||||
| `omniroute setup-crush` | Crush | `~/.config/crush/crush.json` — `openai-compat` provider, key via `$OMNIROUTE_API_KEY` | `--remote` `--api-key` `--only` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-goose` | Goose | `~/.config/goose/config.yaml` (`GOOSE_PROVIDER`/`OPENAI_HOST`/`GOOSE_MODEL`) + prints env recipe | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-aider` | Aider | `~/.aider.conf.yml` (`openai-api-base` + `model: openai/<id>`) + prints env recipe | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` | Both |
|
||||
| `omniroute setup-qwen` | Qwen Code | `~/.qwen/settings.json` — V4 `modelProviders.openai` array + `OMNIROUTE_API_KEY` in `~/.qwen/.env` | `--remote` `--api-key` `--model` `--yes` `--dry-run` `--port` `--config-path` `--env-path` | Both |
|
||||
| `omniroute setup-5dive` | 5dive (agent fleet) | Nothing under `$HOME` — writes a 5dive **auth profile** (`/var/lib/5dive/auth-profiles/<name>/`) via `5dive agent auth set`; root-only, runs on the fleet host | `--remote` `--api-key` `--model` `--auth-profile` `--agent` `--byo-provider` `--fivedive-bin` `--no-sudo` `--yes` `--dry-run` `--port` | Both |
|
||||
| `omniroute run <target>` | Runtime launch (generic) | Nothing — spawn `claude`/`codex`/`aider`/`goose`/`opencode`/`qwen`/`gemini` with the right env and args; Qwen and Gemini use a temporary isolated home | `--remote` `--base-url` `--context` `--provider` `--model` `--api-key` `--api-key-env` `--dry-run` `--json` `--port` `--profile` `--token` | Both |
|
||||
| `omniroute launch` | Claude Code | Nothing — spawns `claude` with `ANTHROPIC_BASE_URL`/`ANTHROPIC_AUTH_TOKEN` injected | `--remote` `--api-key` `--token` `--profile` `--port` | Both |
|
||||
| `omniroute launch-codex` | OpenAI Codex CLI | Nothing — spawns `codex` with the `omniroute` provider injected via `-c` flags | `--remote` `--api-key` `--profile` (`-p`) `--port` | Both |
|
||||
|
||||
Notes on flags (verified in the command source):
|
||||
|
||||
@@ -90,7 +91,7 @@ Notes on flags (verified in the command source):
|
||||
filesystem. Available on every `setup-*` command **except** `setup-cursor`
|
||||
(which never writes a file).
|
||||
- `--model <id>` — required (or picked interactively) for the tools that have no
|
||||
model auto-discovery: Cline, Kilo, Roo, Goose, Qwen, Aider. Those tools
|
||||
model auto-discovery: Cline, Kilo, Roo, Goose, Qwen, Aider, 5dive. Those tools
|
||||
also accept `--yes` for non-interactive runs (which then requires `--model`).
|
||||
`setup-opencode` takes `--model` to set the default top-level model.
|
||||
- `--model <id>` on `omniroute run` follows the manifest's per-target wiring
|
||||
@@ -122,7 +123,8 @@ omniroute configure qwen --model qwen/qwen3.8-max-preview --yes
|
||||
```
|
||||
|
||||
`configure` currently delegates to the tested recipes for `codex`, `claude`,
|
||||
`opencode`, `qwen`, `aider`, `goose`, `cline`, `continue`, and `kilo`. IDE-only,
|
||||
`opencode`, `qwen`, `aider`, `goose`, `cline`, `continue`, `kilo`, and `5dive`.
|
||||
IDE-only,
|
||||
MITM, and guide-only catalog entries remain explicit `setup-*`/manual flows and
|
||||
are not presented as launchable targets.
|
||||
|
||||
@@ -213,6 +215,44 @@ See [Remote Mode](./REMOTE-MODE.md) for contexts, scopes, and token management.
|
||||
|
||||
---
|
||||
|
||||
## 5dive agent fleets
|
||||
|
||||
[5dive](https://5dive.ai) runs a fleet of long-running coding agents, each one a
|
||||
systemd unit under its own Unix user. It is not a coding CLI itself, so there is
|
||||
nothing for `omniroute run` to launch — `5dive` is a **configure-only** target.
|
||||
|
||||
```bash
|
||||
omniroute configure 5dive --model failover-demo --yes
|
||||
omniroute setup-5dive --model failover-demo --auth-profile omniroute --agent worker1
|
||||
```
|
||||
|
||||
Both forms write one 5dive **auth profile**, and every `claude` seat bound to that
|
||||
profile then talks to OmniRoute. Three things are specific to this target:
|
||||
|
||||
- **It runs on the fleet host, as root.** 5dive's verbs act on local systemd units
|
||||
and a root-owned state dir; there is no remote mode. The recipe re-execs through
|
||||
`sudo` when it is not already root (`--no-sudo` turns that off and prints the
|
||||
command instead).
|
||||
- **The endpoint must be `https://` unless it is loopback.** The agent's API key
|
||||
rides that URL on every request, and 5dive refuses a plaintext off-box endpoint.
|
||||
A private LAN address is not an exception.
|
||||
- **Each seat's own model pin outranks the profile.** The profile carries
|
||||
`ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU}_MODEL`, but a seat still pinned to a stock
|
||||
model id fails its first turn with _"There's an issue with the selected model"_.
|
||||
Pass `--agent <name>` (repeatable) to pin the seats as well; the recipe prints the
|
||||
command when you do not.
|
||||
|
||||
The API key is handed to 5dive on **stdin** (`--api-key=-`), so it never appears in
|
||||
`ps` output.
|
||||
|
||||
Pointing the profile at an OmniRoute **combo** rather than a single model is what
|
||||
gets the fleet provider failover: when the primary endpoint went hard-down mid-turn
|
||||
in the run recorded on
|
||||
[#11578](https://github.com/diegosouzapw/OmniRoute/issues/11578), the agent finished
|
||||
its remaining steps on the fallback and never surfaced the outage.
|
||||
|
||||
---
|
||||
|
||||
## Base URL conventions (which tools want `/v1`)
|
||||
|
||||
OmniRoute exposes the OpenAI surface at `/v1`, the Anthropic surface at the root,
|
||||
@@ -229,6 +269,7 @@ tool expects (verified in the command source):
|
||||
| `setup-codex`, `launch-codex` (`model_providers.omniroute.base_url`) | with `/v1` | Yes |
|
||||
| `setup-qwen` (`modelProviders.openai[].baseUrl`) | with `/v1` | Yes |
|
||||
| `run gemini` (`GOOGLE_GEMINI_BASE_URL`) | root | No — the SDK appends `/v1beta/models/…` |
|
||||
| `setup-5dive` (`ANTHROPIC_BASE_URL` in the auth profile) | root | No — Claude Code appends `/v1/messages` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -311,6 +311,7 @@ Beyond the defaults documented in [ENVIRONMENT.md](../reference/ENVIRONMENT.md),
|
||||
| `AUTO_UPDATE_HOST_REPO_DIR` | Host path mounted into `cli` profile at `/workspace/omniroute` for self-update workflows | `.` (current directory) |
|
||||
| `OMNIROUTE_MEMORY_MB` | Runtime Node heap ceiling for the Docker standalone server; overrides the image default above. Coding agents: `8192`+ (see [runtime RAM](#runtime-ram-for-coding-agents)). | `1024` |
|
||||
| `DASHBOARD_PORT` / `API_PORT` | Override exposed ports for dashboard (20128) and API (20129) | `20128` / `20129` |
|
||||
| `OMNIROUTE_PLUGINS_DIR` | Directory the runtime plugin scanner reads and installs into. Set it when plugins are bind-mounted: the default follows `HOME`, which an image need not export. | `~/.omniroute/plugins` |
|
||||
| `OMNIROUTE_BASE_PATH` | URL subpath when the app is published behind a reverse proxy (e.g. `/omniroute`) | _(empty = root)_ |
|
||||
| `NEXT_PUBLIC_BASE_URL` | Public browser origin including the subpath (e.g. `https://host/omniroute`) | unset |
|
||||
| `PROD_DASHBOARD_PORT` | Host-side dashboard port for `docker-compose.prod.yml` | `20130` |
|
||||
|
||||
@@ -75,7 +75,7 @@ When you run `npm install -g omniroute`, you may see a wall of warnings like `np
|
||||
The warnings come from stale peer-dependency ranges in third-party packages OmniRoute doesn't control:
|
||||
|
||||
1. **`marked-terminal` wants `marked >=1 <16`, found `marked@18`** — works fine in practice; the upstream peer range is just stale.
|
||||
2. **`deprecated prebuild-install@7.1.3`** — the native-binary fetch helper. Only relevant later if a web-cookie provider reports a missing `tls-client-node` native binary (a separate issue, not caused by this warning).
|
||||
2. **`deprecated prebuild-install@7.1.3`** — a transitive native-binary helper used by another dependency. The pinned `wreq-js@3.0.0` package bundles its seven supported platform addons directly; this warning does not diagnose the web-cookie transport.
|
||||
|
||||
**No action needed** — the warnings cannot be fully silenced without forking upstream packages.
|
||||
|
||||
@@ -148,9 +148,10 @@ desktop app, for example:
|
||||
- `resources/app/.build/next/node_modules/playwright-<hash>/lib/…/agentParser.js` and
|
||||
`workerProcessEntry.js` — [Playwright](https://playwright.dev), the browser-automation
|
||||
library used for in-app provider login and browser-backed chat.
|
||||
- `resources/app/.build/next/node_modules/tls-client-node-<hash>/bin/tls-client-windows-64-<ver>.dll`
|
||||
— the native binary from `tls-client-node`, used for Cloudflare-tolerant HTTP on some web
|
||||
providers.
|
||||
- `resources/app/.build/next/node_modules/wreq-js-<hash>/rust/wreq-js.win32-x64-msvc.node`
|
||||
— the declared MIT-licensed native addon from pinned `wreq-js@3.0.0`, used for
|
||||
browser-fingerprinted HTTP on some web providers. Its expected SHA-256 is recorded in
|
||||
`config/release/wreq-js-native-manifest.json`.
|
||||
|
||||
**Why it fires:** the Windows installer is **not yet code-signed**, so an unsigned NSIS
|
||||
installer has zero reputation and behavioral heuristics run at maximum aggression. Combined
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
@@ -18,7 +19,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
|
||||
- **Framework:** Next.js 16 (App Router) with TypeScript 6
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 166 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 167 migrations)
|
||||
- **State management:** Zustand (client), SQLite (server persistence)
|
||||
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
|
||||
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
|
||||
@@ -438,7 +439,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
|
||||
|
||||
5. **Database layer:** Operations go through `src/lib/db/` modules (120 domain-specific files, 166 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
|
||||
5. **Database layer:** Operations go through `src/lib/db/` modules (120 domain-specific files, 167 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
|
||||
|
||||
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
@@ -18,7 +19,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
|
||||
- **Framework:** Next.js 16 (App Router) with TypeScript 6
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 166 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 167 migrations)
|
||||
- **State management:** Zustand (client), SQLite (server persistence)
|
||||
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
|
||||
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
|
||||
@@ -438,7 +439,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
|
||||
|
||||
5. **Database layer:** Operations go through `src/lib/db/` modules (120 domain-specific files, 166 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
|
||||
5. **Database layer:** Operations go through `src/lib/db/` modules (120 domain-specific files, 167 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
|
||||
|
||||
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user