mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-18 12:52:25 +03:00
Compare commits
161 Commits
chore/depe
...
feat/i18n-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20c0a0b9f4 | ||
|
|
d0eb0f372b | ||
|
|
8dddc5202b | ||
|
|
f7dbfc88c7 | ||
|
|
d7cbaac9fe | ||
|
|
152d95108c | ||
|
|
cf2d29d2ad | ||
|
|
1b2dd3d282 | ||
|
|
7741aefbf6 | ||
|
|
db6feb6fad | ||
|
|
6dc66921a7 | ||
|
|
b97bc59f4f | ||
|
|
1fb7d5dff2 | ||
|
|
fb8f7d7fa2 | ||
|
|
95ebed770b | ||
|
|
01a66e26c6 | ||
|
|
84bc929dd8 | ||
|
|
f5e8c149cb | ||
|
|
0bdbe48de2 | ||
|
|
2acae48a5a | ||
|
|
8c5eff1bb4 | ||
|
|
bdc2fb76f6 | ||
|
|
2cb02d26c6 | ||
|
|
57d9e74881 | ||
|
|
1361a9dd88 | ||
|
|
0569f420be | ||
|
|
8751f111b2 | ||
|
|
02128f3343 | ||
|
|
c5707e65de | ||
|
|
13ee0f1e73 | ||
|
|
a5db197663 | ||
|
|
660137b3ce | ||
|
|
7a938fe39f | ||
|
|
39abab6681 | ||
|
|
2e872c50aa | ||
|
|
0431db3c62 | ||
|
|
cb55187eda | ||
|
|
b3bee580a8 | ||
|
|
b8b638e649 | ||
|
|
57a37ed858 | ||
|
|
d0b22ddf86 | ||
|
|
bc28bb06b1 | ||
|
|
6207868dc1 | ||
|
|
954f12b202 | ||
|
|
480b190fdc | ||
|
|
10099d037f | ||
|
|
d3a59621bf | ||
|
|
15b26879e6 | ||
|
|
8d52dcabe2 | ||
|
|
ced6ee72b3 | ||
|
|
907ffccd55 | ||
|
|
0b7a6abf48 | ||
|
|
c79caa913a | ||
|
|
9982e37e03 | ||
|
|
2ecb3d5c2d | ||
|
|
f1fc54eeb2 | ||
|
|
fe73a3ad35 | ||
|
|
c4eafaa26d | ||
|
|
359b9b520b | ||
|
|
0b56765e4c | ||
|
|
00f16a2719 | ||
|
|
b85185df59 | ||
|
|
d2bc688b0f | ||
|
|
0c2a5f3062 | ||
|
|
73dee8db43 | ||
|
|
6788b437f5 | ||
|
|
d92bc8ef7a | ||
|
|
f4fd9190b3 | ||
|
|
171421439d | ||
|
|
0cd88ec998 | ||
|
|
9b4210a53f | ||
|
|
9adc2f87d0 | ||
|
|
aedc506cce | ||
|
|
49b6c3e59e | ||
|
|
fc3ce839fe | ||
|
|
541a6481a9 | ||
|
|
f0b83b86ba | ||
|
|
a31c7880c4 | ||
|
|
c75e293a47 | ||
|
|
ba1ee66174 | ||
|
|
374bbe3ee7 | ||
|
|
3f62e43696 | ||
|
|
16c68bad49 | ||
|
|
6caf836092 | ||
|
|
7cd2fab253 | ||
|
|
afd2d993e6 | ||
|
|
e09cb5a768 | ||
|
|
0831d487c0 | ||
|
|
b23b0ca68e | ||
|
|
7ad5e1120e | ||
|
|
a606df0b5d | ||
|
|
00421fde0c | ||
|
|
02884ed8d2 | ||
|
|
3198c54146 | ||
|
|
2e10346f45 | ||
|
|
616d54cf19 | ||
|
|
a0c52ba54d | ||
|
|
4309a2fd56 | ||
|
|
abe234e094 | ||
|
|
455aade660 | ||
|
|
cfa2fc7548 | ||
|
|
a19bb2227f | ||
|
|
cc4f7ed1c4 | ||
|
|
3156643f6c | ||
|
|
9f0d54a48f | ||
|
|
20abd89d7c | ||
|
|
e1cfdb5e48 | ||
|
|
d61b1727cd | ||
|
|
99fb441434 | ||
|
|
67618978b0 | ||
|
|
85a5126dba | ||
|
|
b1733d3c83 | ||
|
|
66330cc724 | ||
|
|
a3fa6cf524 | ||
|
|
30c96d43a5 | ||
|
|
658153c7b0 | ||
|
|
a1b9b02d5d | ||
|
|
178d25250a | ||
|
|
edfcb8be17 | ||
|
|
af49d4972e | ||
|
|
22473dee50 | ||
|
|
2b9e7fb3ec | ||
|
|
9a56147019 | ||
|
|
751247a143 | ||
|
|
567abb5d68 | ||
|
|
403a1a697d | ||
|
|
f2d5728cfd | ||
|
|
0a314c84de | ||
|
|
1929aa656a | ||
|
|
4edc3d57d0 | ||
|
|
a6f28210de | ||
|
|
5df94f8b05 | ||
|
|
e1a1290fde | ||
|
|
ee21e7d2c9 | ||
|
|
fd27ff08c7 | ||
|
|
0549dcfc36 | ||
|
|
393cfdd660 | ||
|
|
d86cf75aef | ||
|
|
e89a4da2b0 | ||
|
|
81bf3cc36e | ||
|
|
955b28ef5c | ||
|
|
a152eb92db | ||
|
|
d6a61074dc | ||
|
|
4c10baa644 | ||
|
|
b516e95262 | ||
|
|
3e2a6d8f35 | ||
|
|
6029515402 | ||
|
|
0ddb47228b | ||
|
|
a0c69ca25e | ||
|
|
590582711c | ||
|
|
7d4189fd78 | ||
|
|
12c7895bbd | ||
|
|
1216cff05b | ||
|
|
2b1c57485c | ||
|
|
91990d606b | ||
|
|
3272bedd1b | ||
|
|
a1b260146d | ||
|
|
13d792c0bb | ||
|
|
9debec71ec | ||
|
|
8ecdd88c15 | ||
|
|
d88fc2bce7 |
@@ -73,6 +73,11 @@ docs/i18n/**
|
||||
# so without this rule these land in /app/docs and become readable through the
|
||||
# dashboard's Docs viewer at runtime.
|
||||
docs/superpowers/**
|
||||
# Operator-internal security writeups: git only, not the image or /docs catalog.
|
||||
docs/security/STEALTH_GUIDE.md
|
||||
docs/security/SOCKET_DEV_FINDINGS.md
|
||||
docs/security/MITM-TPROXY-DECRYPT.md
|
||||
docs/security/PUBLIC_CREDS.md
|
||||
docs/diagrams/**/*.png
|
||||
docs/diagrams/**/*.jpg
|
||||
docs/diagrams/**/*.jpeg
|
||||
|
||||
45
.env.example
45
.env.example
@@ -124,6 +124,21 @@ DISABLE_SQLITE_AUTO_BACKUP=false
|
||||
# Host port for the compose Redis sidecar. Default: 6379.
|
||||
# REDIS_PORT=6379
|
||||
|
||||
# Host interface docker-compose publishes the app's own ports (dashboard,
|
||||
# API, live-WS) on for the base/web/cli/host profiles and docker-compose.prod.yml.
|
||||
# Default: 127.0.0.1 (loopback only). Combined with REQUIRE_API_KEY=false
|
||||
# (the default below), an unqualified publish spec would expose the anonymous
|
||||
# /v1 LLM proxy to your whole LAN/WAN. Only set this to 0.0.0.0 once you've
|
||||
# confirmed REQUIRE_API_KEY=true, or that a reverse proxy in front of this
|
||||
# instance already enforces its own authentication. (#12568)
|
||||
# APP_BIND_HOST=127.0.0.1
|
||||
# Host interface docker-compose publishes the Qdrant memory sidecar on.
|
||||
# Default: 127.0.0.1 (loopback only). Same LAN-exposure reasoning as Redis.
|
||||
# QDRANT_BIND_HOST=127.0.0.1
|
||||
# Host interface docker-compose publishes the Bifrost router sidecar on.
|
||||
# Default: 127.0.0.1 (loopback only). Same LAN-exposure reasoning as Redis.
|
||||
# BIFROST_BIND_HOST=127.0.0.1
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# 3. NETWORK & PORTS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
@@ -373,6 +388,8 @@ AUTH_COOKIE_SECURE=false
|
||||
# Require an API key for all /v1/* proxy endpoints.
|
||||
# Used by: API middleware — rejects unauthenticated requests to the proxy API.
|
||||
# Default: false | Set true for multi-user/public deployments.
|
||||
# Leaving this false is only safe when the app is reachable on loopback only
|
||||
# (see APP_BIND_HOST above) or sits behind a reverse proxy doing its own auth.
|
||||
REQUIRE_API_KEY=false
|
||||
|
||||
# Allow revealing full API key values in the Dashboard UI.
|
||||
@@ -1175,6 +1192,11 @@ CODEX_OAUTH_CLIENT_ID=app_EMoamEEZ73f0CkXaXp7hrann
|
||||
# Trae OAuth token override. Used by: open-sse/executors/trae.ts.
|
||||
# TRAE_TOKEN=
|
||||
|
||||
# Trae web client Origin/Referer override (fleet-wide bump if Trae moves hosts
|
||||
# again without a code change). Default: https://work.trae.ai.
|
||||
# Used by: open-sse/executors/trae.ts.
|
||||
# TRAE_WEB_ORIGIN=https://work.trae.ai
|
||||
|
||||
# ── Gemini / Antigravity (Google-based) ──
|
||||
# These providers ship public OAuth client_id/secret values embedded in their
|
||||
# public CLIs. Defaults are baked into the code via
|
||||
@@ -1311,7 +1333,8 @@ CLAUDE_USER_AGENT="claude-cli/2.1.258 (external, cli)"
|
||||
# stream with a misleading 400 out-of-extra-usage placeholder. Set to true to
|
||||
# forward the original names verbatim (debugging only).
|
||||
# CLAUDE_DISABLE_TOOL_NAME_CLOAK=false
|
||||
CODEX_USER_AGENT="codex-cli/0.144.1 (Windows 10.0.26200; x64)"
|
||||
# Optional override; leave unset to follow the shared Codex client version.
|
||||
# CODEX_USER_AGENT="codex-cli/0.153.4 (Windows 10.0.26200; x64)"
|
||||
GITHUB_USER_AGENT="GitHubCopilotChat/0.54.0"
|
||||
ANTIGRAVITY_USER_AGENT="antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0"
|
||||
KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0"
|
||||
@@ -1331,7 +1354,7 @@ CURSOR_USER_AGENT="Cursor/3.4"
|
||||
|
||||
# Override Codex client version sent in headers independently of the
|
||||
# CODEX_USER_AGENT string. Used by: open-sse/config/codexClient.ts.
|
||||
# CODEX_CLIENT_VERSION=0.144.1
|
||||
# CODEX_CLIENT_VERSION=0.153.4
|
||||
#
|
||||
# Override the advertised Claude Code client version independently of
|
||||
# CLAUDE_USER_AGENT. Anthropic gates some models (Fable 5.1) on this
|
||||
@@ -1646,6 +1669,7 @@ CURSOR_USER_AGENT="Cursor/3.4"
|
||||
|
||||
# ── TLS client (wreq-js fingerprint proxy) ──
|
||||
# TLS_CLIENT_TIMEOUT_MS=600000 # Inherits from FETCH_TIMEOUT_MS by default
|
||||
# TLS_FIRST_BYTE_WATCHDOG_MS=10000 # #12656: bounds time-to-first-byte on the wreq body (0 disables)
|
||||
|
||||
# ── API Bridge (/v1 proxy server) ──
|
||||
# API_BRIDGE_PROXY_TIMEOUT_MS=600000 # Proxy hop timeout (default: 10min)
|
||||
@@ -2077,6 +2101,13 @@ APP_LOG_TO_FILE=true
|
||||
# Management key for an externally managed instance. Embedded instances use
|
||||
# OmniRoute's encrypted service key.
|
||||
# CLIPROXYAPI_MANAGEMENT_KEY=
|
||||
# Host interface docker-compose publishes the cliproxyapi sidecar on (the
|
||||
# --profile cliproxyapi Docker service, port 8317). Default: 127.0.0.1
|
||||
# (loopback only) — its data volume holds provider OAuth/API credentials, and
|
||||
# the pinned image has no env-based data-plane api-keys override (only a
|
||||
# mounted config.yaml), so an unqualified publish spec would put a
|
||||
# credential-bearing service on your whole LAN. (#12578)
|
||||
# CLIPROXY_BIND_HOST=127.0.0.1
|
||||
|
||||
# ── Mux embedded service ──
|
||||
# Override the port where the embedded Mux (coder/mux) agent-orchestration
|
||||
@@ -2721,6 +2752,10 @@ PLAYGROUND_COMPARE_MAX_COLUMNS=4
|
||||
# MEMORY_VEC_TOP_K=20 # default top-K for vector search
|
||||
# MEMORY_RRF_K=60 # RRF k constant (sqlite-vec hybrid recipe)
|
||||
# HF_HUB_ENDPOINT=https://huggingface.co # override Hugging Face Hub base URL for static potion downloads
|
||||
# Test/diagnostic seam (src/lib/memory/vectorStore.ts) — forces getVectorStore() to
|
||||
# return null (simulates a cloud/WASM environment without sqlite-vec), degrading
|
||||
# memory retrieval to FTS5 keyword search. Default off; leave unset in production.
|
||||
# VECTOR_STORE_DISABLE_VEC=false
|
||||
# TV6 typed memory decay (OPT-IN, default off — the sweep DELETES decayed memories)
|
||||
# MEMORY_TYPED_DECAY_ENABLED=false # master switch for the destructive sweep (default off)
|
||||
# MEMORY_TYPED_DECAY_EPISODIC_DAYS=30 # episodic TTL in days; 0 = episodic immune too
|
||||
@@ -2990,6 +3025,7 @@ QUOTA_STORE_DRIVER=sqlite
|
||||
# OMNIROUTE_VNC_READY_MS=45000
|
||||
# OMNIROUTE_VNC_HARVEST_MS=20000
|
||||
# OMNIROUTE_VNC_CHROMIUM_ARGS=--remote-debugging-port=9222 --no-first-run --no-default-browser-check
|
||||
# OMNIROUTE_VNC_NETWORK=omniroute-vnc-browser-login
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Data-dir alias (optional — open-sse/services/notionThreadSessions.ts)
|
||||
@@ -3070,6 +3106,11 @@ QUOTA_STORE_DRIVER=sqlite
|
||||
# Telegram Mini App bridge. The update endpoint remains disabled while the bot
|
||||
# token is unset. Used by: src/lib/telegram/* and src/app/api/telegram/update/route.ts.
|
||||
# TELEGRAM_BOT_TOKEN=
|
||||
# Shared secret registered with setWebhook and echoed back by Telegram as the
|
||||
# X-Telegram-Bot-Api-Secret-Token header. REQUIRED for the webhook path: without
|
||||
# it the webhook is rejected with 503, because an unauthenticated update lets any
|
||||
# caller mint API keys and spend upstream quota. The Mini App path does not use it.
|
||||
# TELEGRAM_WEBHOOK_SECRET=
|
||||
# TELEGRAM_DEFAULT_MODEL=auto/chat
|
||||
# TELEGRAM_BOT_API_BASE=https://api.telegram.org
|
||||
# TELEGRAM_WEBHOOK_TIMEOUT_MS=60000
|
||||
|
||||
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
@@ -142,7 +142,14 @@ jobs:
|
||||
- run: npm run check:known-symbols
|
||||
- run: npm run check:route-guard-membership
|
||||
- run: npm run check:test-discovery
|
||||
- run: npm run check:radar-sentinels
|
||||
- run: npm run check:tracked-artifacts
|
||||
# A test parked in vitest.config.ts's exclude list does not run, and looks like
|
||||
# coverage to whoever reads the tree. 62 files accumulated behind a comment pointing
|
||||
# at #8618 — closed in August while the list grew to 62; 51 of them passed when
|
||||
# finally measured (#13204). This gate requires every exclusion to name a tracker and
|
||||
# to appear in config/quality/vitest-exclusions.json, so the debt stays reviewable.
|
||||
- run: npm run check:vitest-exclusions
|
||||
# (gap 30) Also lives in quality.yml's PR-only "Merge integrity" job — because the
|
||||
# CHANGELOG half of that job needs a base to diff against. This half does NOT: the
|
||||
# generator either reproduces the committed SKILL.md files or it does not.
|
||||
@@ -514,6 +521,16 @@ jobs:
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref && format('origin/{0}', github.base_ref) || '' }}
|
||||
run: node scripts/i18n/check-ui-value-drift.mjs
|
||||
# Sibling of the drift gate above. That one catches an English value that was
|
||||
# REWRITTEN; this one catches an English key that was ADDED while some locales never
|
||||
# got it. The coverage gate at the top of this job cannot: it is a percentage per
|
||||
# locale, and 11 absent keys out of ~13,000 leaves coverage at 99.9%. Incident: the
|
||||
# Phase 3 canvas keys were translated across the 42 locales that existed, then the EU
|
||||
# batch (#13044) took the repo to 51 and the nine newcomers shipped untranslated.
|
||||
- name: i18n new-key coverage (a new key must reach every locale)
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref && format('origin/{0}', github.base_ref) || '' }}
|
||||
run: node scripts/i18n/check-new-key-coverage.mjs
|
||||
|
||||
# #8038: cheap glossary/protected-terms consistency gate —
|
||||
# complements i18n-ui-coverage (key parity) and the ICU `i18n` job below
|
||||
|
||||
5788
.i18n-state.json
5788
.i18n-state.json
File diff suppressed because it is too large
Load Diff
696
@omniroute/opencode-plugin-v2/package-lock.json
generated
696
@omniroute/opencode-plugin-v2/package-lock.json
generated
@@ -22,7 +22,7 @@
|
||||
"node": ">=22.22.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opencode-ai/plugin": "*"
|
||||
"@opencode-ai/plugin": ">=1.18.29 <2"
|
||||
}
|
||||
},
|
||||
"node_modules/@ai-sdk/provider": {
|
||||
@@ -39,9 +39,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
|
||||
"integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
|
||||
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -56,9 +56,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
|
||||
"integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
|
||||
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -73,9 +73,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -90,9 +90,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -107,9 +107,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -124,9 +124,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -141,9 +141,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -158,9 +158,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -175,9 +175,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
|
||||
"integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
|
||||
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -192,9 +192,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -209,9 +209,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
|
||||
"integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
|
||||
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -226,9 +226,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
|
||||
"integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
|
||||
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -243,9 +243,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
|
||||
"integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
|
||||
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@@ -260,9 +260,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
|
||||
"integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
|
||||
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -277,9 +277,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
|
||||
"integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
|
||||
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -294,9 +294,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
|
||||
"integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
|
||||
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -311,7 +311,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.28.1",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -326,9 +328,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -343,9 +345,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -360,9 +362,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -377,9 +379,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -394,9 +396,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -411,9 +413,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -428,9 +430,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -445,9 +447,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
|
||||
"integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
|
||||
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -462,9 +464,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1180,7 +1182,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.1",
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
|
||||
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
@@ -1191,32 +1195,32 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.28.1",
|
||||
"@esbuild/android-arm": "0.28.1",
|
||||
"@esbuild/android-arm64": "0.28.1",
|
||||
"@esbuild/android-x64": "0.28.1",
|
||||
"@esbuild/darwin-arm64": "0.28.1",
|
||||
"@esbuild/darwin-x64": "0.28.1",
|
||||
"@esbuild/freebsd-arm64": "0.28.1",
|
||||
"@esbuild/freebsd-x64": "0.28.1",
|
||||
"@esbuild/linux-arm": "0.28.1",
|
||||
"@esbuild/linux-arm64": "0.28.1",
|
||||
"@esbuild/linux-ia32": "0.28.1",
|
||||
"@esbuild/linux-loong64": "0.28.1",
|
||||
"@esbuild/linux-mips64el": "0.28.1",
|
||||
"@esbuild/linux-ppc64": "0.28.1",
|
||||
"@esbuild/linux-riscv64": "0.28.1",
|
||||
"@esbuild/linux-s390x": "0.28.1",
|
||||
"@esbuild/linux-x64": "0.28.1",
|
||||
"@esbuild/netbsd-arm64": "0.28.1",
|
||||
"@esbuild/netbsd-x64": "0.28.1",
|
||||
"@esbuild/openbsd-arm64": "0.28.1",
|
||||
"@esbuild/openbsd-x64": "0.28.1",
|
||||
"@esbuild/openharmony-arm64": "0.28.1",
|
||||
"@esbuild/sunos-x64": "0.28.1",
|
||||
"@esbuild/win32-arm64": "0.28.1",
|
||||
"@esbuild/win32-ia32": "0.28.1",
|
||||
"@esbuild/win32-x64": "0.28.1"
|
||||
"@esbuild/aix-ppc64": "0.28.2",
|
||||
"@esbuild/android-arm": "0.28.2",
|
||||
"@esbuild/android-arm64": "0.28.2",
|
||||
"@esbuild/android-x64": "0.28.2",
|
||||
"@esbuild/darwin-arm64": "0.28.2",
|
||||
"@esbuild/darwin-x64": "0.28.2",
|
||||
"@esbuild/freebsd-arm64": "0.28.2",
|
||||
"@esbuild/freebsd-x64": "0.28.2",
|
||||
"@esbuild/linux-arm": "0.28.2",
|
||||
"@esbuild/linux-arm64": "0.28.2",
|
||||
"@esbuild/linux-ia32": "0.28.2",
|
||||
"@esbuild/linux-loong64": "0.28.2",
|
||||
"@esbuild/linux-mips64el": "0.28.2",
|
||||
"@esbuild/linux-ppc64": "0.28.2",
|
||||
"@esbuild/linux-riscv64": "0.28.2",
|
||||
"@esbuild/linux-s390x": "0.28.2",
|
||||
"@esbuild/linux-x64": "0.28.2",
|
||||
"@esbuild/netbsd-arm64": "0.28.2",
|
||||
"@esbuild/netbsd-x64": "0.28.2",
|
||||
"@esbuild/openbsd-arm64": "0.28.2",
|
||||
"@esbuild/openbsd-x64": "0.28.2",
|
||||
"@esbuild/openharmony-arm64": "0.28.2",
|
||||
"@esbuild/sunos-x64": "0.28.2",
|
||||
"@esbuild/win32-arm64": "0.28.2",
|
||||
"@esbuild/win32-ia32": "0.28.2",
|
||||
"@esbuild/win32-x64": "0.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-check": {
|
||||
@@ -1786,490 +1790,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
|
||||
"integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/android-arm": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
|
||||
"integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/android-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
|
||||
"integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
|
||||
"integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
|
||||
"integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
|
||||
"integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
|
||||
"integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
|
||||
"integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
|
||||
"integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
|
||||
"integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
|
||||
"integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
|
||||
"integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tsup/node_modules/esbuild": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
|
||||
"integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.27.7",
|
||||
"@esbuild/android-arm": "0.27.7",
|
||||
"@esbuild/android-arm64": "0.27.7",
|
||||
"@esbuild/android-x64": "0.27.7",
|
||||
"@esbuild/darwin-arm64": "0.27.7",
|
||||
"@esbuild/darwin-x64": "0.27.7",
|
||||
"@esbuild/freebsd-arm64": "0.27.7",
|
||||
"@esbuild/freebsd-x64": "0.27.7",
|
||||
"@esbuild/linux-arm": "0.27.7",
|
||||
"@esbuild/linux-arm64": "0.27.7",
|
||||
"@esbuild/linux-ia32": "0.27.7",
|
||||
"@esbuild/linux-loong64": "0.27.7",
|
||||
"@esbuild/linux-mips64el": "0.27.7",
|
||||
"@esbuild/linux-ppc64": "0.27.7",
|
||||
"@esbuild/linux-riscv64": "0.27.7",
|
||||
"@esbuild/linux-s390x": "0.27.7",
|
||||
"@esbuild/linux-x64": "0.27.7",
|
||||
"@esbuild/netbsd-arm64": "0.27.7",
|
||||
"@esbuild/netbsd-x64": "0.27.7",
|
||||
"@esbuild/openbsd-arm64": "0.27.7",
|
||||
"@esbuild/openbsd-x64": "0.27.7",
|
||||
"@esbuild/openharmony-arm64": "0.27.7",
|
||||
"@esbuild/sunos-x64": "0.27.7",
|
||||
"@esbuild/win32-arm64": "0.27.7",
|
||||
"@esbuild/win32-ia32": "0.27.7",
|
||||
"@esbuild/win32-x64": "0.27.7"
|
||||
}
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.22.3",
|
||||
"dev": true,
|
||||
|
||||
@@ -63,5 +63,8 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opencode-ai/plugin": ">=1.18.29 <2"
|
||||
},
|
||||
"overrides": {
|
||||
"esbuild": "^0.28.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
OmniRouteRawCombo,
|
||||
OmniRouteRawModelEntry,
|
||||
} from "./shared/index.js";
|
||||
import { isHttpUrl } from "./shared/index.js";
|
||||
|
||||
export const DEFAULT_MODEL_CACHE_TTL_MS = 300_000 as const;
|
||||
|
||||
@@ -34,8 +35,9 @@ export const SNAPSHOT_FORMAT_VERSION = 2 as const;
|
||||
|
||||
/**
|
||||
* A raw snapshot entry is stale when it cannot be mapped to a publishable
|
||||
* model: no string `id` (unroutable) or a pre-mapped `api` block without a
|
||||
* valid `npm` package (the runner would reject it as `Unsupported package`).
|
||||
* model: no string `id` (unroutable), or a pre-mapped `api` block missing a
|
||||
* valid `npm` package (the runner would reject it as `Unsupported package`)
|
||||
* or a usable `url` (the host would reach the AI SDK with no baseURL).
|
||||
* Plain `/v1/models` entries carry no `api` block -- it is synthesized at
|
||||
* publish time -- so only a present-but-invalid block drops the entry.
|
||||
*/
|
||||
@@ -47,7 +49,11 @@ export function isStaleSnapshotModel(entry: unknown): boolean {
|
||||
if (api === undefined) return false;
|
||||
if (!api || typeof api !== "object") return true;
|
||||
const npm = (api as { npm?: unknown }).npm;
|
||||
return typeof npm !== "string" || npm.length === 0;
|
||||
if (typeof npm !== "string" || npm.length === 0) return true;
|
||||
// Same requirement as `npm`, and the same predicate the options schema
|
||||
// applies to `baseURL`: a pre-mapped block without a callable `url` publishes
|
||||
// a model the host cannot route -- see `legacyApiToInfoApi`.
|
||||
return !isHttpUrl((api as { url?: unknown }).url);
|
||||
}
|
||||
|
||||
interface DiskSnapshotV2 {
|
||||
@@ -145,7 +151,7 @@ export async function readDiskSnapshot(
|
||||
(entry) => !isStaleSnapshotModel(entry)
|
||||
);
|
||||
if (stale > 0) {
|
||||
logger?.warn(`[omniroute-v2] dropping ${stale} stale snapshot entries without api block`);
|
||||
logger?.warn(`[omniroute-v2] dropping ${stale} stale snapshot entries with an unusable api block`);
|
||||
}
|
||||
if (models.length === 0) return undefined;
|
||||
return {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { type HostContract, detectHostContract, emitsLegacyFields } from "./comp
|
||||
import type { Model as LegacyModelV2 } from "@opencode-ai/sdk/v2";
|
||||
import type { ModelV2Info, ProviderV2Info } from "@opencode-ai/sdk/v2/types";
|
||||
import {
|
||||
isHttpUrl,
|
||||
type ApiFormatV2,
|
||||
type LogLevel,
|
||||
type Logger,
|
||||
@@ -142,6 +143,15 @@ export function legacyApiToInfoApi(api: LegacyModelV2["api"]): ModelV2Info["api"
|
||||
"[omniroute-v2] refusing to publish a model without an api block (missing api.npm)"
|
||||
);
|
||||
}
|
||||
// The host reads `api.url` in `prepareOptions` and never falls back to the
|
||||
// provider's own, so a model published without one reaches the AI SDK with no
|
||||
// baseURL and fails at call time with a bare `Invalid URL` — no request on the
|
||||
// wire, nothing in the gateway logs, no model named.
|
||||
if (!isHttpUrl(api.url)) {
|
||||
throw new Error(
|
||||
"[omniroute-v2] refusing to publish a model whose api block carries no http(s) url"
|
||||
);
|
||||
}
|
||||
return { id: api.id, type: "aisdk", package: api.npm, url: api.url };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { isHttpUrl } from "./shared/models-map.js";
|
||||
|
||||
const apiFormatSchema = z
|
||||
.object({
|
||||
allowAnthropic: z.boolean().optional(),
|
||||
@@ -28,7 +30,10 @@ const pluginOptionsSchema = z
|
||||
.regex(/^[A-Za-z0-9._-]+$/, "providerId may only contain letters, digits, '.', '_' and '-'")
|
||||
.refine((v) => v !== "." && v !== "..", "providerId cannot be a path segment")
|
||||
.default("omniroute"),
|
||||
baseURL: z.string().url(),
|
||||
baseURL: z
|
||||
.string()
|
||||
.trim()
|
||||
.refine(isHttpUrl, "baseURL must be an http(s) URL, for example http://localhost:20128"),
|
||||
apiKey: z.string().optional(),
|
||||
displayName: z.string().optional(),
|
||||
managementReadToken: z.string().optional(),
|
||||
|
||||
@@ -111,6 +111,22 @@ function trimTrailingSlashes(value: string): string {
|
||||
* (it appends `/v1/messages` automatically), so callers should branch on
|
||||
* format first.
|
||||
*/
|
||||
/**
|
||||
* A url the AI SDK can actually call. `new URL()` alone is not enough: it
|
||||
* parses `localhost:20128` as the scheme `localhost:` and `ftp://host` as ftp,
|
||||
* both of which reach `fetch` and fail there. Mirrors the `isHttpUrl` guard the
|
||||
* settings schema applies to `headroomUrl`.
|
||||
*/
|
||||
export function isHttpUrl(value: unknown): boolean {
|
||||
if (typeof value !== "string") return false;
|
||||
try {
|
||||
const { protocol } = new URL(value);
|
||||
return protocol === "http:" || protocol === "https:";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function ensureV1Suffix(url: string): string {
|
||||
const trimmed = trimTrailingSlashes(url);
|
||||
return trimmed.endsWith("/v1") ? trimmed : `${trimmed}/v1`;
|
||||
|
||||
@@ -6,6 +6,33 @@ interface CapturedCall {
|
||||
kind: "catalog" | "integration";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until `read()` stops changing, then return the settled value.
|
||||
*
|
||||
* The plugin's optional tier lands asynchronously after a publish. Waiting for
|
||||
* it with a fixed `sleep(5)` raced the work: under load the tier arrived after
|
||||
* the sleep, so the *next* assertion counted its reload and read 2 where it
|
||||
* expected 1. Polling until the value holds steady for a few consecutive turns
|
||||
* ties the wait to the work instead of to the clock.
|
||||
*/
|
||||
async function settle<T>(read: () => T, quietTurns = 3, timeoutMs = 5000): Promise<T> {
|
||||
const { setTimeout: sleep } = await import("node:timers/promises");
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let last = read();
|
||||
let stable = 0;
|
||||
while (stable < quietTurns && Date.now() < deadline) {
|
||||
await sleep(5);
|
||||
const current = read();
|
||||
if (current === last) {
|
||||
stable += 1;
|
||||
} else {
|
||||
last = current;
|
||||
stable = 0;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
interface FakeCtx {
|
||||
options: Record<string, unknown>;
|
||||
catalog: {
|
||||
@@ -163,7 +190,6 @@ describe("plugin-v2 entrypoint", () => {
|
||||
const { mkdtempSync } = await import("node:fs");
|
||||
const { tmpdir } = await import("node:os");
|
||||
const { join } = await import("node:path");
|
||||
const { setTimeout: sleep } = await import("node:timers/promises");
|
||||
const dir = mkdtempSync(join(tmpdir(), "omniroute-lazy-"));
|
||||
const prevDataDir = process.env.OPENCODE_DATA_DIR;
|
||||
process.env.OPENCODE_DATA_DIR = dir;
|
||||
@@ -222,16 +248,15 @@ describe("plugin-v2 entrypoint", () => {
|
||||
await cb(draft);
|
||||
assert.equal(reloads, 0, "the first publish sets the baseline, it does not reload");
|
||||
assert.equal(modelsCall, 1);
|
||||
await sleep(5);
|
||||
// The optional tier lands after that first publish and brings combos and
|
||||
// the overlay with it — one reload, so the picker shows them without
|
||||
// waiting for the next refresh.
|
||||
const afterFirstUpgrade = reloads;
|
||||
const afterFirstUpgrade = await settle(() => reloads);
|
||||
assert.ok(afterFirstUpgrade <= 1, `at most one reload for the first upgrade, got ${reloads}`);
|
||||
await cb(draft);
|
||||
assert.equal(reloads, afterFirstUpgrade + 1, "a new model id reloads once");
|
||||
assert.equal(modelsCall, 2);
|
||||
await sleep(5);
|
||||
await settle(() => reloads);
|
||||
await cb(draft);
|
||||
assert.equal(reloads, afterFirstUpgrade + 1, "an identical run never reloads");
|
||||
assert.equal(modelsCall, 3);
|
||||
|
||||
@@ -29,6 +29,38 @@ describe("parsePluginOptions", () => {
|
||||
it("requires baseURL", () => {
|
||||
assert.throws(() => parsePluginOptions({}), /baseURL/);
|
||||
});
|
||||
it("rejects a baseURL that is not an http(s) URL", () => {
|
||||
// `new URL()` reads "localhost:20128" as the scheme "localhost:" followed
|
||||
// by a path, so a gateway address typed without "http://" parses. Every
|
||||
// model would then be published with "localhost:20128/v1" as its api url
|
||||
// and every call would fail in the client on an unknown scheme, with no
|
||||
// request on the wire and nothing in the gateway logs.
|
||||
for (const baseURL of [
|
||||
"localhost:20128",
|
||||
"localhost:20128/v1",
|
||||
"ftp://gw.example.com/v1",
|
||||
"gw.example.com/v1",
|
||||
]) {
|
||||
assert.throws(
|
||||
() => parsePluginOptions({ baseURL }),
|
||||
/baseURL must be an http\(s\) URL/,
|
||||
`expected ${baseURL} to be rejected`
|
||||
);
|
||||
}
|
||||
});
|
||||
it("accepts http and https baseURLs, with or without a port or path", () => {
|
||||
for (const baseURL of [
|
||||
"http://localhost:20128/v1",
|
||||
"http://localhost:20128",
|
||||
"https://gw.example.com/v1",
|
||||
"https://gw.example.com/omniroute/v1",
|
||||
]) {
|
||||
assert.equal(parsePluginOptions({ baseURL }).baseURL, baseURL);
|
||||
// Padding a copied address is trimmed rather than rejected, matching the
|
||||
// treatment `headroomUrl` already gets in the settings schema.
|
||||
assert.equal(parsePluginOptions({ baseURL: ` ${baseURL} ` }).baseURL, baseURL);
|
||||
}
|
||||
});
|
||||
it("rejects unknown top-level keys (strict)", () => {
|
||||
assert.throws(() => parsePluginOptions({ baseURL: "https://gw.example.com", bogus: 1 }));
|
||||
});
|
||||
|
||||
@@ -5,7 +5,11 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { createHash } from "node:crypto";
|
||||
import plugin from "../src/index.js";
|
||||
import { diskSnapshotPath, snapshotIdentityFingerprint } from "../src/cache.js";
|
||||
import {
|
||||
diskSnapshotPath,
|
||||
isStaleSnapshotModel,
|
||||
snapshotIdentityFingerprint,
|
||||
} from "../src/cache.js";
|
||||
import { legacyApiToInfoApi } from "../src/catalog.js";
|
||||
|
||||
function isolateDisk(): { dir: string; restore: () => void } {
|
||||
@@ -97,7 +101,7 @@ function downFetch(): typeof fetch {
|
||||
const fingerprint = snapshotIdentityFingerprint("https://gw.example.com", "k-snapfix", "k-snapfix");
|
||||
|
||||
describe("plugin-v2 snapshot stale-entry filter", () => {
|
||||
it("snapshot with 2 entries without api block + 1 valid: only the valid one is published + warn emitted", async () => {
|
||||
it("snapshot with 3 unusable pre-mapped entries + 1 valid: only the valid one is published + warn emitted", async () => {
|
||||
const disk = isolateDisk();
|
||||
const providerId = "snapfix-mixed";
|
||||
mkdirSync(join(disk.dir, "plugins"), { recursive: true });
|
||||
@@ -106,11 +110,15 @@ describe("plugin-v2 snapshot stale-entry filter", () => {
|
||||
JSON.stringify({
|
||||
v: 2,
|
||||
identityFingerprint: fingerprint,
|
||||
// Two pre-mapped entries with a broken api block (missing npm) plus
|
||||
// one plain raw entry (no api block: synthesized at publish time).
|
||||
// Three pre-mapped entries with an unusable api block — missing npm,
|
||||
// empty npm, and a well-formed npm with no url (the shape a snapshot
|
||||
// written by an older build carries, and the one that reaches the host
|
||||
// as a bare `Invalid URL`) — plus one plain raw entry, which has no api
|
||||
// block at all and gets one synthesized at publish time.
|
||||
models: [
|
||||
{ id: "stale-a", api: {} },
|
||||
{ id: "stale-b", api: { npm: "" } },
|
||||
{ id: "stale-c", api: { id: "openai-compatible", npm: "@ai-sdk/openai-compatible" } },
|
||||
{ id: "good-1", context_length: 128000 },
|
||||
],
|
||||
combos: [],
|
||||
@@ -137,7 +145,7 @@ describe("plugin-v2 snapshot stale-entry filter", () => {
|
||||
);
|
||||
});
|
||||
assert.ok(
|
||||
warns.some((w) => w.includes("dropping 2 stale snapshot entries without api block")),
|
||||
warns.some((w) => w.includes("dropping 3 stale snapshot entries with an unusable api block")),
|
||||
`expected stale-drop warn, got: ${JSON.stringify(warns)}`
|
||||
);
|
||||
} finally {
|
||||
@@ -216,4 +224,56 @@ describe("plugin-v2 snapshot stale-entry filter", () => {
|
||||
// Sanity: sha256 helper used above matches the plugin identity scheme.
|
||||
assert.equal(createHash("sha256").update("x").digest("hex").length, 64);
|
||||
});
|
||||
|
||||
it("legacyApiToInfoApi throws unless api.url is an http(s) url", () => {
|
||||
const npm = "@ai-sdk/openai-compatible";
|
||||
for (const api of [
|
||||
{ id: "openai-compatible", npm },
|
||||
{ id: "openai-compatible", npm, url: "" },
|
||||
{ id: "openai-compatible", npm, url: " " },
|
||||
// Non-empty but uncallable: the AI SDK reaches `fetch` and fails there.
|
||||
{ id: "openai-compatible", npm, url: "/v1" },
|
||||
{ id: "openai-compatible", npm, url: "gw.example.com/v1" },
|
||||
{ id: "openai-compatible", npm, url: "ftp://gw.example.com/v1" },
|
||||
]) {
|
||||
assert.throws(
|
||||
() => legacyApiToInfoApi(api as unknown as { id: string; npm: string; url: string }),
|
||||
/api block carries no http\(s\) url/,
|
||||
`expected a publish-time refusal for ${JSON.stringify(api)}`
|
||||
);
|
||||
}
|
||||
// A complete block still publishes unchanged.
|
||||
assert.deepEqual(
|
||||
legacyApiToInfoApi({
|
||||
id: "openai-compatible",
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
url: "https://gw.example.com/v1",
|
||||
}),
|
||||
{
|
||||
id: "openai-compatible",
|
||||
type: "aisdk",
|
||||
package: "@ai-sdk/openai-compatible",
|
||||
url: "https://gw.example.com/v1",
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("isStaleSnapshotModel drops a pre-mapped entry whose api.url is unusable", () => {
|
||||
const npm = "@ai-sdk/openai-compatible";
|
||||
// Present-but-unusable url: stale, for the same reason a missing npm is.
|
||||
for (const url of [undefined, "", " ", "/v1", "gw.example.com/v1", "ftp://gw/v1"]) {
|
||||
assert.equal(
|
||||
isStaleSnapshotModel({ id: "a/b", api: { id: "x", npm, ...(url === undefined ? {} : { url }) } }),
|
||||
true,
|
||||
`expected ${JSON.stringify(url)} to be treated as stale`
|
||||
);
|
||||
}
|
||||
// Complete block: publishable.
|
||||
assert.equal(
|
||||
isStaleSnapshotModel({ id: "a/b", api: { id: "x", npm, url: "https://gw/v1" } }),
|
||||
false
|
||||
);
|
||||
// No api block at all stays publishable: it is synthesized at publish time.
|
||||
assert.equal(isStaleSnapshotModel({ id: "a/b" }), false);
|
||||
});
|
||||
});
|
||||
|
||||
6
@omniroute/opencode-plugin/package-lock.json
generated
6
@omniroute/opencode-plugin/package-lock.json
generated
@@ -1745,9 +1745,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/toml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz",
|
||||
"integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-4.3.0.tgz",
|
||||
"integrity": "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"overrides": {
|
||||
"esbuild": "^0.28.1"
|
||||
"esbuild": "^0.28.1",
|
||||
"toml": "^4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,11 @@ const optionsSchema = z
|
||||
* to 60000. Default when unset: 300000.
|
||||
*/
|
||||
autoSyncIntervalMs: z.number().int().nonnegative().optional(),
|
||||
baseURL: z.string().url().optional(),
|
||||
baseURL: z
|
||||
.string()
|
||||
.trim()
|
||||
.refine(isHttpUrl, "baseURL must be an http(s) URL, for example http://localhost:20128")
|
||||
.optional(),
|
||||
managementReadToken: z.string().min(1).optional(),
|
||||
features: featuresSchema.optional(),
|
||||
})
|
||||
@@ -482,6 +486,22 @@ export const DEFAULT_ANTHROPIC_PREFIXES = ["cc", "claude", "anthropic", "kiro",
|
||||
* (it appends `/v1/messages` automatically), so callers should branch on
|
||||
* format first.
|
||||
*/
|
||||
/**
|
||||
* A url the AI SDK can actually call. `new URL()` alone is not enough: it
|
||||
* parses `localhost:20128` as the scheme `localhost:` and `ftp://host` as ftp,
|
||||
* both of which reach `fetch` and fail there. Mirrors the `isHttpUrl` guard the
|
||||
* settings schema applies to `headroomUrl`.
|
||||
*/
|
||||
export function isHttpUrl(value: unknown): boolean {
|
||||
if (typeof value !== "string") return false;
|
||||
try {
|
||||
const { protocol } = new URL(value);
|
||||
return protocol === "http:" || protocol === "https:";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function ensureV1Suffix(url: string): string {
|
||||
const trimmed = trimTrailingSlashes(url);
|
||||
return trimmed.endsWith("/v1") ? trimmed : `${trimmed}/v1`;
|
||||
|
||||
@@ -59,6 +59,26 @@ test("parseOmniRoutePluginOptions: invalid baseURL (not a URL) → throws", () =
|
||||
assert.throws(() => parseOmniRoutePluginOptions({ baseURL: "not-a-url" }), /baseURL/i);
|
||||
});
|
||||
|
||||
test("parseOmniRoutePluginOptions: baseURL without an http(s) scheme → throws", () => {
|
||||
// `new URL()` reads "localhost:20128" as the scheme "localhost:" followed by
|
||||
// a path, so the address parses and the models are published with an api url
|
||||
// no client can call.
|
||||
for (const baseURL of ["localhost:20128", "localhost:20128/v1", "ftp://or.example.com", "or.example.com"]) {
|
||||
assert.throws(
|
||||
() => parseOmniRoutePluginOptions({ baseURL }),
|
||||
/baseURL must be an http\(s\) URL/,
|
||||
`expected ${baseURL} to be rejected`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("parseOmniRoutePluginOptions: http and https baseURLs are accepted, padding trimmed", () => {
|
||||
for (const baseURL of ["http://localhost:20128", "https://or.example.com/v1"]) {
|
||||
assert.equal(parseOmniRoutePluginOptions({ baseURL }).baseURL, baseURL);
|
||||
assert.equal(parseOmniRoutePluginOptions({ baseURL: ` ${baseURL} ` }).baseURL, baseURL);
|
||||
}
|
||||
});
|
||||
|
||||
test("parseOmniRoutePluginOptions: unknown key → throws (strict mode catches typos)", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
|
||||
19
AGENTS.md
19
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 (172 migrations) |
|
||||
| Database | `src/lib/db/` | SQLite domain modules (173 migrations) |
|
||||
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
|
||||
| MCP Server | `open-sse/mcp-server/` | 110 tools (45 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 |
|
||||
@@ -578,14 +578,31 @@ own dedicated branch, and you MUST confirm the base branch with the operator bef
|
||||
# HARD LINKS (`cp -al`), never a symlink: ~5s for the whole tree and near-zero extra
|
||||
# disk (the inodes are shared), and unlike a symlink it does not break the dev server.
|
||||
cp -al "$(git -C <main_checkout> rev-parse --show-toplevel)/node_modules" node_modules
|
||||
# `.husky/_` is gitignored, so a fresh worktree does NOT have it and
|
||||
# `core.hooksPath=.husky/_` then points at a directory that does not exist —
|
||||
# every pre-commit gate goes silently mute. Copy it too.
|
||||
cp -a "$(git -C <main_checkout> rev-parse --show-toplevel)/.husky/_" .husky/_
|
||||
```
|
||||
|
||||
`scripts/dev/new-worktree.sh <branch> [base]` does all of the above (canonical path,
|
||||
hard-linked `node_modules`, `.husky/_`) and then **verifies** the hook is actually
|
||||
executable, so prefer it over running the steps by hand.
|
||||
|
||||
**Never `ln -s` node_modules.** Turbopack rejects a symlink that resolves outside the
|
||||
project root, so `npm run dev` dies with a FATAL panic (`Symlink [project]/node_modules
|
||||
is invalid, it points out of the filesystem root`) while typecheck, lint and the test
|
||||
runners all keep passing — the error names "filesystem root", not the worktree, so it
|
||||
reads like a Next/build bug and costs real time to trace (incident 2026-07-31, #9043).
|
||||
|
||||
**A worktree without `.husky/_` runs NO pre-commit gate — and says nothing.** `git`
|
||||
resolves `core.hooksPath` relative to the worktree top; when the directory is missing it
|
||||
simply finds no hook and commits. Nothing is printed, the commit succeeds, and the
|
||||
identity/lint/docs gates never ran. This is how 59 commits carrying a stale identity
|
||||
override (name of a contributor + the maintainer's e-mail) got past
|
||||
`scripts/check/check-git-identity.sh` between 2026-08-29 and 09-02 — they were all made in
|
||||
`cp -al` worktrees. Verify with `ls .husky/_/pre-commit` inside a new worktree, or just use
|
||||
`scripts/dev/new-worktree.sh`, which fails loudly when the hook is not executable.
|
||||
|
||||
3. **Work, commit, push, open the PR — all from inside the worktree.** Never `git checkout` a
|
||||
different branch inside a worktree another session might share.
|
||||
4. **Tear down only your own** worktree + branch when done, from the main checkout:
|
||||
|
||||
@@ -340,7 +340,7 @@ RUN --mount=type=cache,id=s/92ca8a61-c1ba-421f-a389-d48ac7258c2d-apt-cache,targe
|
||||
# build, not the floating `@latest`.
|
||||
RUN --mount=type=cache,id=s/92ca8a61-c1ba-421f-a389-d48ac7258c2d-npm-cache,target=/root/.npm \
|
||||
npm install -g --no-audit --no-fund \
|
||||
@openai/codex@0.153.2 \
|
||||
@openai/codex@0.153.4 \
|
||||
@anthropic-ai/claude-code@2.1.260 \
|
||||
droid@0.212.0 \
|
||||
openclaw@2026.9.1
|
||||
|
||||
21
README.md
21
README.md
@@ -133,7 +133,7 @@
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<b>🌐 In 42 languages</b>
|
||||
<b>🌐 In 59 languages</b>
|
||||
<br/><br/>
|
||||
<a href="README.md"><img src="docs/assets/flags/us.svg" width="30" alt="English (en)" title="English (en)"></a>
|
||||
<a href="docs/i18n/pt-BR/README.md"><img src="docs/assets/flags/br.svg" width="30" alt="Português — Brasil (pt-BR)" title="Português — Brasil (pt-BR)"></a>
|
||||
@@ -177,6 +177,23 @@
|
||||
<a href="docs/i18n/tr/README.md"><img src="docs/assets/flags/tr.svg" width="30" alt="Türkçe (tr)" title="Türkçe (tr)"></a>
|
||||
<a href="docs/i18n/az/README.md"><img src="docs/assets/flags/az.svg" width="30" alt="Azərbaycan (az)" title="Azərbaycan (az)"></a>
|
||||
<a href="docs/i18n/sw/README.md"><img src="docs/assets/flags/tz.svg" width="30" alt="Kiswahili (sw)" title="Kiswahili (sw)"></a>
|
||||
<a href="docs/i18n/el/README.md"><img src="docs/assets/flags/gr.svg" width="30" alt="Ελληνικά (el)" title="Ελληνικά (el)"></a>
|
||||
<a href="docs/i18n/hr/README.md"><img src="docs/assets/flags/hr.svg" width="30" alt="Hrvatski (hr)" title="Hrvatski (hr)"></a>
|
||||
<a href="docs/i18n/sr/README.md"><img src="docs/assets/flags/rs.svg" width="30" alt="Српски (sr)" title="Српски (sr)"></a>
|
||||
<a href="docs/i18n/lt/README.md"><img src="docs/assets/flags/lt.svg" width="30" alt="Lietuvių (lt)" title="Lietuvių (lt)"></a>
|
||||
<a href="docs/i18n/et/README.md"><img src="docs/assets/flags/ee.svg" width="30" alt="Eesti (et)" title="Eesti (et)"></a>
|
||||
<a href="docs/i18n/lv/README.md"><img src="docs/assets/flags/lv.svg" width="30" alt="Latviešu (lv)" title="Latviešu (lv)"></a>
|
||||
<a href="docs/i18n/sl/README.md"><img src="docs/assets/flags/si.svg" width="30" alt="Slovenščina (sl)" title="Slovenščina (sl)"></a>
|
||||
<a href="docs/i18n/mt/README.md"><img src="docs/assets/flags/mt.svg" width="30" alt="Malti (mt)" title="Malti (mt)"></a>
|
||||
<a href="docs/i18n/ga/README.md"><img src="docs/assets/flags/ie.svg" width="30" alt="Gaeilge (ga)" title="Gaeilge (ga)"></a>
|
||||
<a href="docs/i18n/kn/README.md"><img src="docs/assets/flags/in.svg" width="30" alt="ಕನ್ನಡ (kn)" title="ಕನ್ನಡ (kn)"></a>
|
||||
<a href="docs/i18n/ml/README.md"><img src="docs/assets/flags/in.svg" width="30" alt="മലയാളം (ml)" title="മലയാളം (ml)"></a>
|
||||
<a href="docs/i18n/or/README.md"><img src="docs/assets/flags/in.svg" width="30" alt="ଓଡ଼ିଆ (or)" title="ଓଡ଼ିଆ (or)"></a>
|
||||
<a href="docs/i18n/pa/README.md"><img src="docs/assets/flags/in.svg" width="30" alt="ਪੰਜਾਬੀ (pa)" title="ਪੰਜਾਬੀ (pa)"></a>
|
||||
<a href="docs/i18n/ne/README.md"><img src="docs/assets/flags/np.svg" width="30" alt="नेपाली (ne)" title="नेपाली (ne)"></a>
|
||||
<a href="docs/i18n/si/README.md"><img src="docs/assets/flags/lk.svg" width="30" alt="සිංහල (si)" title="සිංහල (si)"></a>
|
||||
<a href="docs/i18n/my/README.md"><img src="docs/assets/flags/mm.svg" width="30" alt="မြန်မာ (my)" title="မြန်မာ (my)"></a>
|
||||
<a href="docs/i18n/km/README.md"><img src="docs/assets/flags/kh.svg" width="30" alt="ខ្មែរ (km)" title="ខ្មែរ (km)"></a>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
@@ -1244,7 +1261,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) — 122 domain modules, 172 migrations</td></tr>
|
||||
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 122 domain modules, 173 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>
|
||||
|
||||
@@ -54,6 +54,34 @@ async function openBrowser(url) {
|
||||
}
|
||||
}
|
||||
|
||||
// Mirrors src/lib/oauth/providers.ts::isLoopbackHostname — used here to detect
|
||||
// when the redirect_uri the server resolved (and the authorize URL now
|
||||
// advertises) points at a loopback address the CLI never binds a listener on
|
||||
// (issue #12413). Returns false on an unparseable URI rather than throwing.
|
||||
function isLoopbackHost(uri) {
|
||||
try {
|
||||
return /^(localhost|127\.0\.0\.1|\[::1\]|::1)$/i.test(new URL(uri).hostname);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function printLoopbackRedirectWarning(providerId, redirectUri) {
|
||||
process.stdout.write(
|
||||
`Note: the authorize URL below advertises ${redirectUri}, but this CLI does not\n` +
|
||||
"listen on that port. Right after you approve, the browser is expected to\n" +
|
||||
"show a connection error (e.g. \"This site can't be reached\" / \n" +
|
||||
"ERR_CONNECTION_REFUSED) — that is normal, not a failure. Copy the full URL\n" +
|
||||
"from the address bar anyway and paste it below.\n"
|
||||
);
|
||||
if (providerId === "antigravity") {
|
||||
process.stdout.write(
|
||||
"Tip: `omniroute login antigravity` captures the code automatically and\n" +
|
||||
"avoids that error page entirely.\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function targetApiOptions(opts = {}) {
|
||||
return {
|
||||
baseUrl: opts.baseUrl,
|
||||
@@ -110,6 +138,10 @@ async function runBrowserFlow(def, opts) {
|
||||
const { codeVerifier, state, redirectUri: returnedRedirectUri } = start;
|
||||
const finalRedirectUri = returnedRedirectUri || redirectUri;
|
||||
|
||||
if (finalRedirectUri && isLoopbackHost(finalRedirectUri)) {
|
||||
printLoopbackRedirectWarning(def.id, finalRedirectUri);
|
||||
}
|
||||
|
||||
process.stdout.write(`\nOpen this URL to authorize:\n ${url}\n\n`);
|
||||
if (opts.browser !== false) await openBrowser(url);
|
||||
process.stdout.write(
|
||||
|
||||
@@ -35,16 +35,24 @@ export function resolveOpencodeTarget(opts = {}) {
|
||||
baseUrl = `http://localhost:${Number(opts.port ?? process.env.PORT ?? 20128) || 20128}`;
|
||||
}
|
||||
|
||||
// Precedence: explicit --api-key flag > OMNIROUTE_API_KEY env var > active
|
||||
// context's management token. A context's accessToken/apiKey is a CLI
|
||||
// management credential (oma_live_...) with no /v1/* inference scope — it
|
||||
// must never silently outrank a real inference key the caller supplied
|
||||
// either as a flag or via the ambient env var (mirrors the explicit >
|
||||
// ambient-env > context precedence documented in bin/cli/api.mjs's
|
||||
// buildHeaders()). Only fall back to the context token when neither an
|
||||
// explicit flag nor the env var is set.
|
||||
let apiKey = opts.apiKey ?? opts["api-key"];
|
||||
if (!apiKey) apiKey = process.env.OMNIROUTE_API_KEY || "";
|
||||
if (!apiKey) {
|
||||
try {
|
||||
const c = resolveActiveContext(opts.context ?? process.env.OMNIROUTE_CONTEXT);
|
||||
apiKey = c?.accessToken || c?.apiKey;
|
||||
apiKey = c?.accessToken || c?.apiKey || "";
|
||||
} catch {
|
||||
/* no context auth */
|
||||
}
|
||||
}
|
||||
if (!apiKey) apiKey = process.env.OMNIROUTE_API_KEY || "";
|
||||
return { baseUrl: baseUrl.replace(/\/+$/, ""), apiKey };
|
||||
}
|
||||
|
||||
@@ -177,8 +185,17 @@ export function registerSetupOpencode(program) {
|
||||
"--allow-container-write",
|
||||
"Write even when the target is inside a container and not mounted from the host"
|
||||
)
|
||||
.action(async (opts) => {
|
||||
const code = await runSetupOpencodeCommand(opts);
|
||||
.action(async (opts, cmd) => {
|
||||
// Commander parses the ancestor program's own global --api-key option
|
||||
// (bin/cli/program.mjs, bound to .env("OMNIROUTE_API_KEY")) against any
|
||||
// occurrence of the flag in argv, so it wins the value even when the
|
||||
// user typed --api-key AFTER `setup-opencode` — this local option's own
|
||||
// `opts.apiKey` never sees it. cmd.optsWithGlobals() resolves to the
|
||||
// correct value either way ("globals overwrite locals" is exactly the
|
||||
// outcome we want here, since the global option is where the value
|
||||
// always actually lands).
|
||||
const resolvedOpts = { ...opts, apiKey: cmd.optsWithGlobals().apiKey ?? opts.apiKey };
|
||||
const code = await runSetupOpencodeCommand(resolvedOpts);
|
||||
if (code !== 0) process.exit(code);
|
||||
});
|
||||
}
|
||||
|
||||
1329
bin/cli/locales/el.json
Normal file
1329
bin/cli/locales/el.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/et.json
Normal file
1329
bin/cli/locales/et.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/ga.json
Normal file
1329
bin/cli/locales/ga.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/hr.json
Normal file
1329
bin/cli/locales/hr.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/km.json
Normal file
1329
bin/cli/locales/km.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/kn.json
Normal file
1329
bin/cli/locales/kn.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/lt.json
Normal file
1329
bin/cli/locales/lt.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/lv.json
Normal file
1329
bin/cli/locales/lv.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/ml.json
Normal file
1329
bin/cli/locales/ml.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/mt.json
Normal file
1329
bin/cli/locales/mt.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/my.json
Normal file
1329
bin/cli/locales/my.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/ne.json
Normal file
1329
bin/cli/locales/ne.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/or.json
Normal file
1329
bin/cli/locales/or.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/pa.json
Normal file
1329
bin/cli/locales/pa.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/si.json
Normal file
1329
bin/cli/locales/si.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/sl.json
Normal file
1329
bin/cli/locales/sl.json
Normal file
File diff suppressed because it is too large
Load Diff
1329
bin/cli/locales/sr.json
Normal file
1329
bin/cli/locales/sr.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,34 @@ if (isVersionFastPath(process.argv)) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Detect an unsupported Node.js runtime BEFORE the heavy `tsx/esm` import and
|
||||
// Commander's ~70-command registration chain run. That chain pulls in `ora` ->
|
||||
// the hoisted `string-width` package, whose module contains top-level ES2024
|
||||
// Unicode-set (`v` flag) regex literals. On a Node/V8 build that predates
|
||||
// `v`-flag support, those literals fail to even *parse*, throwing a bare
|
||||
// `SyntaxError: Invalid regular expression flags` deep inside a transitive
|
||||
// dependency instead of an actionable message (#12296). Skip this for the
|
||||
// same read-only invocations `shouldProvisionStorageKey` already exempts
|
||||
// (`--help`/`-h`, `help`/`completion`) — those still need the full command
|
||||
// registry to render their output, so an incompatible runtime crashing there
|
||||
// is a separate, pre-existing limitation this fix does not attempt to solve.
|
||||
if (shouldProvisionStorageKey(process.argv)) {
|
||||
const nodeSupport = getNodeRuntimeSupport();
|
||||
if (!nodeSupport.nodeCompatible) {
|
||||
const runtimeWarning = getNodeRuntimeWarning() || "Unsupported Node.js runtime detected.";
|
||||
console.error(
|
||||
`\x1b[31m✖ Node.js ${nodeSupport.nodeVersion} is not supported.\x1b[0m\n` +
|
||||
` ${runtimeWarning}\n` +
|
||||
` Supported runtimes: ${nodeSupport.supportedDisplay}\n` +
|
||||
` Recommended: Node.js ${nodeSupport.recommendedVersion}\n` +
|
||||
` If you installed OmniRoute globally, run \`node -v\` and confirm \`omniroute\` is not resolving to\n` +
|
||||
` a stale/distro-packaged \`nodejs\` binary (e.g. /usr/bin/node) instead of the version you expect —\n` +
|
||||
` that mismatch is the most common cause even when package.json's engines range is correct.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// MCP stdio transport uses stdout exclusively for JSON-RPC messages. Redirect
|
||||
// console.log/warn to stderr before anything else runs — including the tsx/esm and
|
||||
// polyfill imports below, since those (and their transitive module graphs, e.g. DB
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- **feat(gamification): pay the documented `streak_bonus` and `badge_unlock` XP rewards.** `XP_REWARDS` listed both rewards but the award pipeline never paid them: the private reward table in `events.ts` omitted them, `updateStreak()` did not report when a streak extended, and badge unlocks carried no XP. Every request that extends a daily streak now pays `streak_bonus × streak length` once per UTC day (guarded by a same-day `xp_audit_log` check), and every badge unlocked through the pipeline pays `badge_unlock` once per badge (guarded by the `user_badges` primary key; `unlockBadge()` now reports whether it inserted). Bonus XP flows through the same `addXp` + level sync + global/weekly/monthly leaderboard path as action XP, so level-ups and rankings include it. The Radar supporter recognition unlock stays XP-free. (#12522 — thanks @pacocartones)
|
||||
1
changelog.d/features/12985-eurouter-provider.md
Normal file
1
changelog.d/features/12985-eurouter-provider.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(providers):** Added EURouter as an OpenAI-compatible API-key gateway (`https://api.eurouter.ai/v1`), with live model discovery via `passthroughModels`. Its copy states that models are served by third-party upstreams listed per model, so an EU-based router is not read as EU data residency for inference.
|
||||
1
changelog.d/features/12986-greenpt-provider.md
Normal file
1
changelog.d/features/12986-greenpt-provider.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(providers):** Added GreenPT as an OpenAI-compatible API-key provider (`https://api.greenpt.ai/v1`), with live model discovery via `passthroughModels`. No free-inference badge: the published docs describe a free API subscription billed per token, not a free tier.
|
||||
1
changelog.d/features/13044-i18n-batch-eu.md
Normal file
1
changelog.d/features/13044-i18n-batch-eu.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(i18n):** 9 new locales — Greek (`el`), Croatian (`hr`), Serbian (`sr`), Lithuanian (`lt`), Estonian (`et`), Latvian (`lv`), Slovenian (`sl`), Maltese (`mt`), Irish (`ga`) — across the dashboard, docs mirrors, CLI, README and the site; OmniRoute now ships every official EU language (51 locales). (#13044)
|
||||
1
changelog.d/features/13660-i18n-batch-sa.md
Normal file
1
changelog.d/features/13660-i18n-batch-sa.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(i18n):** 8 new locales — Kannada (`kn`), Malayalam (`ml`), Odia (`or`), Punjabi (`pa`), Nepali (`ne`), Sinhala (`si`), Burmese (`my`), Khmer (`km`) — across the dashboard, docs mirrors, CLI, README and the site (59 locales). The translator now restores the ICU literal escape around angle placeholders and splits oversized docs sections before translating. (#0000)
|
||||
1
changelog.d/features/agnes-30-flash-catalog.md
Normal file
1
changelog.d/features/agnes-30-flash-catalog.md
Normal file
@@ -0,0 +1 @@
|
||||
- feat(providers): **list Agnes 3.0 Flash as the current free chat model, drop retired 1.5 Flash, add Image 2.0/2.5 Flash plus Video 2.5/2.5 Flash, and discover the live `/v1/models` catalog (including the CN host `api.agnes-ai.cn`).** `agnes-1.5-flash` now forwards to `agnes-3.0-flash`. Video 2.5 polls `GET /v1/videos/{id}` (not the V2.0 `/agnesapi` contract). Live `/v1/models` (2026-09-09) no longer serves 1.5; the wiki marks it deprecated. 3.0 Flash is 512K context / 65,536 max output, same window as 2.5. CN-region keys use the existing per-connection base-URL field, default stays `apihub.agnes-ai.com`.
|
||||
1
changelog.d/features/codex-gpt-6-astra.md
Normal file
1
changelog.d/features/codex-gpt-6-astra.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(sse):** Codex and OpenAI catalogs list GPT-6 Astra with effort aliases (`-low` through `-ultra`); Codex CLI identity pins `@openai/codex@0.153.4` in lockstep with the image ([#13026](https://github.com/diegosouzapw/OmniRoute/pull/13026))
|
||||
11
changelog.d/features/orchestration-compare-runs.md
Normal file
11
changelog.d/features/orchestration-compare-runs.md
Normal file
@@ -0,0 +1,11 @@
|
||||
- **feat(dashboard):** the orchestration History tab gained a "Compare runs" mode — toggling it
|
||||
turns each grid cell into a 2-item selection queue (a 3rd click drops the oldest pick), and
|
||||
picking two cells opens a side-by-side comparison panel instead of the usual detail drawer.
|
||||
The panel fetches both runs' detail the same way the drawer does (falling back to persisted
|
||||
history once a run leaves the live TTL window) and shows, per side: identity/source/state,
|
||||
start time, a signed `right - left` delta for duration/cost/event count, the event timeline
|
||||
aligned by index, and any memory hits. One side's fetch failing never blocks the other, and a
|
||||
delta is only ever computed when both sides have a finite value — otherwise it renders "—",
|
||||
never `NaN`. Comparing two runs from different sources or skills still works; a banner marks
|
||||
the deltas as informational rather than hiding them, since the two runs aren't a strict
|
||||
apples-to-apples pair.
|
||||
1
changelog.d/fixes/0000-responses-node-model-test.md
Normal file
1
changelog.d/fixes/0000-responses-node-model-test.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(dashboard):** model health tests for a provider node set to the Responses API now call `/v1/responses` with a Responses-shaped body instead of `/v1/chat/completions` — those models were reported as `Provider returned HTTP 200 but no text content` even though the same model answered normally through `/v1/responses` ([#13070](https://github.com/diegosouzapw/OmniRoute/issues/13070))
|
||||
@@ -0,0 +1 @@
|
||||
- fix(routing): stop a round-robin combo's "opencode" targets from collapsing onto the opencode-zen connection (#11912)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(routing): stop the reactive-compaction debug log from lying when compression is globally disabled (#11977)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(electron): relativize standalone-bundle symlink targets so Stage 8 manifest verification stops failing on Windows (#11979)
|
||||
1
changelog.d/fixes/12061-compression-studio-run-error.md
Normal file
1
changelog.d/fixes/12061-compression-studio-run-error.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(dashboard): surface a visible error when Compression Studio's combined preview run fails (#12061)
|
||||
1
changelog.d/fixes/12063-compression-profile-header.md
Normal file
1
changelog.d/fixes/12063-compression-profile-header.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(dashboard): make the compression "Effective pipeline" preview honor the active profile and warn when the master switch is off (#12063)
|
||||
1
changelog.d/fixes/12072-tinycms-dom-shim-leak.md
Normal file
1
changelog.d/fixes/12072-tinycms-dom-shim-leak.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(providers): scope TinyCMS Web signer's DOM shims to each call instead of leaking them for the process lifetime, and surface a clean HTTP status on a non-JSON interception-toggles error (#12072)
|
||||
1
changelog.d/fixes/12111-vision-bridge-model-lockout.md
Normal file
1
changelog.d/fixes/12111-vision-bridge-model-lockout.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(guardrails): stop Vision Bridge from re-selecting a model locked after a 404 (#12111)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(sse): require Responses-shaped body before native OpenAI-compatible passthrough (#12129)
|
||||
1
changelog.d/fixes/12132-minimax-m3-adaptive-thinking.md
Normal file
1
changelog.d/fixes/12132-minimax-m3-adaptive-thinking.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(providers): minimax-m3 now collapses manual thinking.type:"enabled" to adaptive, preventing upstream 400 (2013) (#12132)
|
||||
1
changelog.d/fixes/12172-model-id-collision-chat-image.md
Normal file
1
changelog.d/fixes/12172-model-id-collision-chat-image.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(db): scope model visibility overrides by modality so hiding a Chat model no longer hides an identically-ID'd Image/Embeddings/etc. model (#12172)
|
||||
1
changelog.d/fixes/12173-lmstudio-multi-account.md
Normal file
1
changelog.d/fixes/12173-lmstudio-multi-account.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(db): scope local-provider apiKey dedup to matching base URL so LM Studio/Ollama-style connections support multiple accounts (#12173)
|
||||
1
changelog.d/fixes/12190-trae-referer-401.md
Normal file
1
changelog.d/fixes/12190-trae-referer-401.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(providers): refresh Trae's stale Referer/Origin and forward user timezone so imported connections stop failing with 401 (#12190)
|
||||
1
changelog.d/fixes/12196-opencode-go-gpt56luna.md
Normal file
1
changelog.d/fixes/12196-opencode-go-gpt56luna.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(providers): route opencode-go/gpt-5.6-luna to /responses instead of /chat/completions (#12196)
|
||||
1
changelog.d/fixes/12251-extra-upstream-headers-delete.md
Normal file
1
changelog.d/fixes/12251-extra-upstream-headers-delete.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(dashboard): allow deleting the last extra-upstream-header row even when invalid (#12251)
|
||||
1
changelog.d/fixes/12272-missing-i18n.md
Normal file
1
changelog.d/fixes/12272-missing-i18n.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(i18n):** translate pre-existing `__MISSING__:` keys for `combo.sort`, `requestLogger.detail` expand/collapse, `common.profile`, and `settings.resilienceCredentialHealth*` across 39 locales ([#12272](https://github.com/diegosouzapw/OmniRoute/issues/12272))
|
||||
1
changelog.d/fixes/12296-node-runtime-guard-early.md
Normal file
1
changelog.d/fixes/12296-node-runtime-guard-early.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(cli): run the Node.js runtime compatibility guard before the heavy `tsx/esm` + Commander import chain so an unsupported runtime gets a clear message instead of a raw `Invalid regular expression flags` crash (#12296)
|
||||
1
changelog.d/fixes/12298-provider-node-delete-refresh.md
Normal file
1
changelog.d/fixes/12298-provider-node-delete-refresh.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(dashboard): refresh the providers list after deleting a compatible provider node (#12298)
|
||||
1
changelog.d/fixes/12341-budget-alias-auto.md
Normal file
1
changelog.d/fixes/12341-budget-alias-auto.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(usage): fail closed on API-key budget enforcement when a provider's `auto` routing alias has no pricing row, instead of silently counting it as $0 (#12341)
|
||||
1
changelog.d/fixes/12356-agnes-video-poll-model-name.md
Normal file
1
changelog.d/fixes/12356-agnes-video-poll-model-name.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(providers):** include the submitted Agnes video model when polling by `video_id`
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(routing):** custom OpenAI-compatible nodes now honor the saved Chat/Responses API type after edits instead of letting the node's original ID prefix override the live connection setting ([#11884](https://github.com/diegosouzapw/OmniRoute/issues/11884)).
|
||||
1
changelog.d/fixes/12398-claude-truly-empty-stream.md
Normal file
1
changelog.d/fixes/12398-claude-truly-empty-stream.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(sse): surface an error instead of a silent empty 200 when a Claude stream closes with zero bytes (#12398)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(oauth): warn before the dead localhost:8080 redirect in antigravity/gemini `oauth start` (#12413)
|
||||
1
changelog.d/fixes/12517-devin-cli-sse-double-close.md
Normal file
1
changelog.d/fixes/12517-devin-cli-sse-double-close.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(providers): stop devin-cli spawn error from double-closing the SSE controller (#12517)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(rerank):** clamp Voyage `top_k` to the documents actually sent after empty-string filtering, and honor `return_documents: false` in the NVIDIA response adapter (#12523 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(audio):** `/v1/audio/translations` now resolves combo names the way `/v1/audio/transcriptions` already does, so a combo that `GET /v1/models` advertises is fanned out to its targets instead of being rejected with `400 Invalid translation model: <combo>. Use format: provider/model`; literal `provider/model` ids and unknown bare names behave as before (#12536 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(gemini):** strip the JSON-Schema-2020-12 `prefixItems` keyword from Gemini tool schemas at every nesting level, so Claude Code tool definitions no longer fail with `400 Unknown name "prefixItems"` on Gemini models (#12540 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(api-manager):** Expose an accessible loading status while API keys are fetched instead of an empty accessibility tree (#12541 — thanks @pacocartones)
|
||||
1
changelog.d/fixes/12543-video-frame-estimate-clamp.md
Normal file
1
changelog.d/fixes/12543-video-frame-estimate-clamp.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(video):** Clamp `estimateJpegFrameBytes` at zero for padding-only payloads and build the three encode-side frame data URIs from `JPEG_FRAME_DATA_URI_PREFIX` instead of a repeated literal (#12543 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(devin):** accept Windows `DEVIN_AGENTIC_HOME` sandbox paths (`C:\...\.sandbox\...`) in the isolated-home check so the Devin Claude Bridge no longer fails closed on Windows ([#12405](https://github.com/diegosouzapw/OmniRoute/issues/12405)) (#12545 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(db):** Add `conversation_turn_nodes` and orphaned `agentic_conversations` to the auto-cleanup cycle under the existing `retention.callLogs` window, so identity nodes whose call-log content has already been purged no longer accumulate without bound in `storage.sqlite` (#12548 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(i18n):** Wrap the `~/.claude/profiles/<name>/settings.json` placeholder in ICU single quotes in the `OMNIROUTE_AUTO_SYNC_CLAUDE_PROFILES` feature-flag description across all 42 locales and the TypeScript default, so next-intl no longer fails with `INVALID_MESSAGE: UNCLOSED_TAG` and the Feature Flags card shows the description instead of the raw key (#12549 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(orchestration):** `updateCloudAgentTask` now publishes the task's real `status` on `agent.task.updated` when an update only touches `result`, `activities` or `error`, instead of the fabricated `"updated"` state, and stays silent when no row matched the id (#12550 — thanks @pacocartones)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(i18n):** the home "Recent Requests" panel and the Provider Topology legend are now translated instead of rendering English copies on non-English dashboards; the legend reads its own `home.topologyLegend*` labels with consistent casing rather than borrowing the memory-settings "Recent" and analytics "Error" strings (#12551 — thanks @pacocartones).
|
||||
1
changelog.d/fixes/12552-feature-flags-reference-sync.md
Normal file
1
changelog.d/fixes/12552-feature-flags-reference-sync.md
Normal file
@@ -0,0 +1 @@
|
||||
- **docs(reference):** bring the `FEATURE_FLAGS.md` catalog back to 1:1 with `featureFlagDefinitions.ts` — 20 missing flags added, the two `*_BLOCK_THRESHOLD` env-only knobs moved out of the flag tables, category/total counts and the Live WS port corrected, guarded by a static test (#12552 — thanks @pacocartones)
|
||||
1
changelog.d/fixes/12561-kilo-pass-i18n.md
Normal file
1
changelog.d/fixes/12561-kilo-pass-i18n.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(i18n):** backfill missing `usage.kiloPass*` strings in 39 locales and restore `featureFlagOmnirouteDisableThinkingLevelVariantsDescription` in `pt.json` ([#12561](https://github.com/diegosouzapw/OmniRoute/issues/12561)) — thanks @HouMinXi
|
||||
1
changelog.d/fixes/12568-compose-loopback-bind.md
Normal file
1
changelog.d/fixes/12568-compose-loopback-bind.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(docker): default docker-compose app ports (dashboard/API/live-WS) to loopback instead of `0.0.0.0`, closing the anonymous `/v1` LAN/WAN exposure gap left open by `REQUIRE_API_KEY=false` (#12568)
|
||||
1
changelog.d/fixes/12569-webhook-dns-rebinding-ssrf.md
Normal file
1
changelog.d/fixes/12569-webhook-dns-rebinding-ssrf.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(api): close DNS-rebinding SSRF gap in webhook outbound-URL guard (#12569)
|
||||
1
changelog.d/fixes/12571-vnc-cdp-bridge-auth.md
Normal file
1
changelog.d/fixes/12571-vnc-cdp-bridge-auth.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(docker): require a per-session token on the VNC browser CDP bridge and isolate it on a dedicated Docker network (#12571)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(open-sse): write Adobe Firefly session tokens and cookie jars with 0700/0600 permissions instead of the process umask (#12572)
|
||||
1
changelog.d/fixes/12573-gemini-cors-wildcard.md
Normal file
1
changelog.d/fixes/12573-gemini-cors-wildcard.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(api): remove hardcoded wildcard CORS in openai-to-gemini-sse.ts so the centralized fail-closed CORS gate is the sole source of `Access-Control-Allow-Origin` (#12573)
|
||||
1
changelog.d/fixes/12574-elevenlabs-policy-enforcement.md
Normal file
1
changelog.d/fixes/12574-elevenlabs-policy-enforcement.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(api): enforce API key policy (budget/rate-limit/schedule/endpoint scoping) on the ElevenLabs speech-to-text, text-to-speech and voices proxy routes (#12574)
|
||||
1
changelog.d/fixes/12577-huggingchat-buffer-cap.md
Normal file
1
changelog.d/fixes/12577-huggingchat-buffer-cap.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(sse): cap HuggingChat NDJSON body size and bound the read loop with the fetch timeout so a stalled or hostile upstream cannot buffer unbounded memory (#12577)
|
||||
1
changelog.d/fixes/12578-cliproxyapi-loopback-bind.md
Normal file
1
changelog.d/fixes/12578-cliproxyapi-loopback-bind.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(docker): scope the cliproxyapi/qdrant/bifrost sidecars to loopback by default and forward `CLIPROXYAPI_MANAGEMENT_KEY` into the cliproxyapi container so its management API is not left both unauthenticated and LAN-published (#12578)
|
||||
1
changelog.d/fixes/12579-db-export-tempdir-mkdtemp.md
Normal file
1
changelog.d/fixes/12579-db-export-tempdir-mkdtemp.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(api): create DB export temp paths with `fs.mkdtempSync` instead of predictable timestamps (#12579)
|
||||
1
changelog.d/fixes/12594-cline-401-oauth.md
Normal file
1
changelog.d/fixes/12594-cline-401-oauth.md
Normal file
@@ -0,0 +1 @@
|
||||
- Cline 401 bodies that say "re-authenticate your Cline account" classify as a refreshable OAuth token, not a terminal expired key. The cooling panel no longer labels every cooldown as a 429; it shows the recorded last error instead. (#12594)
|
||||
1
changelog.d/fixes/12613-combo-openrouter-modalities.md
Normal file
1
changelog.d/fixes/12613-combo-openrouter-modalities.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(catalog):** degrade unknown combo targets instead of dropping LCD modalities, and persist OpenRouter `architecture.input_modalities` into the capability snapshot ([#12613](https://github.com/diegosouzapw/OmniRoute/issues/12613))
|
||||
@@ -0,0 +1 @@
|
||||
- fix(providers): send `x-api-key` instead of `Authorization: Bearer` for OpenCode Zen's `/v1/responses` endpoint (Muse Spark Contributor models), fixing a 401 on OmniRoute's auth header (#12633)
|
||||
@@ -0,0 +1 @@
|
||||
- fix(sse): surface the actionable "Auggie CLI not found" message when the shell reports a missing `auggie` binary via exit code instead of a spawn error (#12645)
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(config):** Persist deletions of built-in background-degradation entries — when a stored settings record exists its `degradationMap` is now authoritative instead of being merged under the defaults, so an entry the user removed in the dashboard no longer reappears on the next apply or restart ([#12424](https://github.com/diegosouzapw/OmniRoute/issues/12424))
|
||||
1
changelog.d/fixes/12651-action-count-durable-counters.md
Normal file
1
changelog.d/fixes/12651-action-count-durable-counters.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(gamification):** action-count badge milestones (First Token, Token Consumer, Token Machine, Token Whale, and the token-sharing tier) are now backed by a durable `xp_action_counts` counter incremented in `addXp()`, instead of a live `COUNT(*)` over `xp_audit_log`. The audit log is pruned by `retention.xpAuditLog` (default 30 days), so on a default install those "lifetime" milestones were really "actions in the last 30 days" and unlocked badges could stop unlocking once old rows aged out. `getActionCount()` and `checkActionCountBadges()` now read the same durable source, and a migration backfills existing totals from the surviving audit rows ([#12546](https://github.com/diegosouzapw/OmniRoute/issues/12546))
|
||||
1
changelog.d/fixes/12653-image-combo-edits-fallback.md
Normal file
1
changelog.d/fixes/12653-image-combo-edits-fallback.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(images):** `/v1/images/edits` now iterates a combo's targets the same way `/v1/images/generations` does (#9239) instead of flattening a bare combo to its first target. A combo whose first target is not edit-capable — or lacks credentials — now falls through to a later edit-capable target rather than hard-erroring, and missing credentials are skipped (not a hard `401`) to match the generations path. The per-target skip/terminal classification is extracted into a shared `runImageComboTargets` loop, so generations behavior is unchanged ([#12547](https://github.com/diegosouzapw/OmniRoute/issues/12547)).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user