node dependency updates (#2259)

chore: node dependency updates (#2259 — thanks @backryun)
This commit is contained in:
backryun
2026-05-15 08:20:54 +09:00
committed by GitHub
parent aa0e312d8a
commit c6b269a4d5
32 changed files with 1556 additions and 766 deletions

View File

@@ -92,7 +92,7 @@ OMNIROUTE_USE_TURBOPACK=1
# OMNIROUTE_PORT=20128
# Hostname/bind address for the Next.js server.
# Used by: scripts/run-next.mjs (HOST), Playwright runner (HOSTNAME).
# Used by: scripts/dev/run-next.mjs (HOST), Playwright runner (HOSTNAME).
# Default: 0.0.0.0 (HOST) / 127.0.0.1 (HOSTNAME inside tests).
#HOST=0.0.0.0
#HOSTNAME=127.0.0.1
@@ -955,7 +955,7 @@ APP_LOG_TO_FILE=true
# Used by: open-sse/utils/cursorVersionDetector.ts. Default: probed automatically.
# CURSOR_STATE_DB_PATH=
# Direct Cursor bearer token used by scripts/cursor-tap.cjs (developer tooling).
# Direct Cursor bearer token used by scripts/ad-hoc/cursor-tap.cjs (developer tooling).
# CURSOR_TOKEN=
# Log Responses API SSE-to-JSON translation details.
@@ -1073,8 +1073,8 @@ APP_LOG_TO_FILE=true
# ═══════════════════════════════════════════════════════════════════════════════
# 25. TEST & E2E
# ═══════════════════════════════════════════════════════════════════════════════
# Used by scripts/run-next-playwright.mjs, scripts/smoke-electron-packaged.mjs,
# scripts/run-ecosystem-tests.mjs and scripts/uninstall.mjs.
# Used by scripts/dev/run-next-playwright.mjs, scripts/dev/smoke-electron-packaged.mjs,
# scripts/dev/run-ecosystem-tests.mjs and scripts/build/uninstall.mjs.
# Production deployments should leave every value below unset.
# E2E bootstrap mode for the Playwright runner. Accepted: auth | fresh | reuse.
@@ -1116,7 +1116,7 @@ APP_LOG_TO_FILE=true
# Number of parallel translation requests (default 4).
# OMNIROUTE_TRANSLATION_CONCURRENCY=4
# Electron smoke harness (used by scripts/smoke-electron-packaged.mjs).
# Electron smoke harness (used by scripts/dev/smoke-electron-packaged.mjs).
# ELECTRON_SMOKE_URL=http://127.0.0.1:20128/login
# ELECTRON_SMOKE_TIMEOUT_MS=45000
# ELECTRON_SMOKE_SETTLE_MS=2000

View File

@@ -165,7 +165,7 @@ body:
description: "Which commands or tests should prove this bug is fixed?"
placeholder: |
Example:
- node --import tsx/esm --test tests/unit/my-file.test.ts
- node --import tsx --test tests/unit/my-file.test.ts
- npm run test:coverage
validations:
required: false

View File

@@ -59,7 +59,7 @@ body:
description: "List the commands that must pass before this issue can be closed."
placeholder: |
Example:
- node --import tsx/esm --test tests/unit/my-suite.test.ts
- node --import tsx --test tests/unit/my-suite.test.ts
- npm run test:coverage
validations:
required: true

View File

@@ -207,7 +207,7 @@ jobs:
cache: npm
- run: npm ci
- run: npm run check:node-runtime
- run: node --import tsx/esm --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
- run: node --import tsx --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
node-24-compat:
name: Node 24 Compatibility (${{ matrix.shard }}/2)
@@ -231,7 +231,7 @@ jobs:
- run: npm ci
- run: npm run check:node-runtime
- run: npm run build
- run: node --import tsx/esm --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
- run: node --import tsx --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
node-26-compat:
name: Node 26 Compatibility (${{ matrix.shard }}/2)
@@ -255,7 +255,7 @@ jobs:
- run: npm ci
- run: npm run check:node-runtime
- run: npm run build
- run: node --import tsx/esm --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
- run: node --import tsx --test --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/unit/*.test.ts
test-coverage:
name: Coverage
@@ -462,7 +462,7 @@ jobs:
cache: npm
- run: npm ci
- run: npm run check:node-runtime
- run: node --import tsx/esm --test --test-force-exit --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/integration/*.test.ts
- run: node --import tsx --test --test-force-exit --test-concurrency=1 --test-shard=${{ matrix.shard }}/2 tests/integration/*.test.ts
test-security:
name: Security Tests

View File

@@ -360,7 +360,7 @@ async function checkNativeBinary(rootDir) {
try {
const { isNativeBinaryCompatible } = await import(
pathToFileURL(path.join(rootDir, "scripts", "native-binary-compat.mjs")).href
pathToFileURL(path.join(rootDir, "scripts", "build", "native-binary-compat.mjs")).href
);
const compatible = isNativeBinaryCompatible(binaryPath);
if (!compatible) {

View File

@@ -37,7 +37,7 @@ export async function startMcpCli(rootDir = ROOT) {
}
// `tsx` loader is only required for local `.ts` fallback; JS entry works without it.
const loaderArgs = mcpEntry.endsWith(".ts") ? ["--import", "tsx/esm"] : [];
const loaderArgs = mcpEntry.endsWith(".ts") ? ["--import", "tsx"] : [];
await new Promise((resolve, reject) => {
const child = spawn(process.execPath, [...loaderArgs, mcpEntry], {

View File

@@ -22,7 +22,7 @@ import { existsSync, readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { homedir, platform } from "node:os";
import { isNativeBinaryCompatible } from "../scripts/native-binary-compat.mjs";
import { isNativeBinaryCompatible } from "../scripts/build/native-binary-compat.mjs";
import { getNodeRuntimeSupport, getNodeRuntimeWarning } from "./nodeRuntimeSupport.mjs";
const __filename = fileURLToPath(import.meta.url);

View File

@@ -106,7 +106,7 @@ OmniRoute uses **SQLite** (via `better-sqlite3`) for all persistence. These vari
## 3. Network & Ports
| Variable | Default | Source File | Description |
| ------------------------- | ------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ------------------------- | ------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PORT` | `20128` | `src/lib/runtime/ports.ts` | Primary port for both Dashboard UI and API endpoints (single-port mode). |
| `API_PORT` | _(unset)_ | `src/lib/runtime/ports.ts` | When set, serves the `/v1/*` proxy API on this separate port. |
| `API_HOST` | `0.0.0.0` | `src/lib/runtime/ports.ts` | Bind address for the API port. |
@@ -116,8 +116,8 @@ OmniRoute uses **SQLite** (via `better-sqlite3`) for all persistence. These vari
| `OMNIROUTE_PORT` | _(unset)_ | `src/lib/runtime/ports.ts` | Takes precedence over `PORT` when running inside Electron or other wrappers. |
| `NODE_ENV` | `production` | Next.js core | Controls logging verbosity, caching, error detail exposure, and Next.js optimizations. |
| `OMNIROUTE_USE_TURBOPACK` | `1` (default in `.env.example`) | `package.json` / Next.js 16 | Toggles the Next.js 16 Turbopack bundler in `npm run dev` and `npm run build`. Set to `0` on Windows or when running into native binding incompatibilities. |
| `HOST` | `0.0.0.0` | `scripts/run-next.mjs` | Bind address for the Next.js dev/start server. Overrides the default `0.0.0.0` when set. |
| `HOSTNAME` | `127.0.0.1` | `scripts/run-next-playwright.mjs` | Bind address used by the Playwright runner when launching Next.js. Defaults to `127.0.0.1` for hermetic tests. |
| `HOST` | `0.0.0.0` | `scripts/dev/run-next.mjs` | Bind address for the Next.js dev/start server. Overrides the default `0.0.0.0` when set. |
| `HOSTNAME` | `127.0.0.1` | `scripts/dev/run-next-playwright.mjs` | Bind address used by the Playwright runner when launching Next.js. Defaults to `127.0.0.1` for hermetic tests. |
### Port Modes
@@ -666,7 +666,7 @@ Anthropic-compatible provider instead.
| `CURSOR_DUMP_FILE` | _(unset)_ | `open-sse/executors/cursor.ts` | Optional file path that receives raw decoded Cursor chunks when `CURSOR_DEBUG=1`. |
| `CURSOR_STREAM_TIMEOUT_MS` | `300000` | `open-sse/executors/cursor.ts` | Stream idle timeout (ms) for the Cursor executor. |
| `CURSOR_STATE_DB_PATH` | _(probed)_ | `open-sse/utils/cursorVersionDetector.ts` | Override the Cursor state DB lookup used for version detection. |
| `CURSOR_TOKEN` | _(unset)_ | `scripts/cursor-tap.cjs` | Direct Cursor bearer token used by developer tooling. |
| `CURSOR_TOKEN` | _(unset)_ | `scripts/ad-hoc/cursor-tap.cjs` | Direct Cursor bearer token used by developer tooling. |
| `OMNIROUTE_LOG_REQUEST_SHAPE` | enabled (`!== "0"`) | `src/app/api/v1/chat/completions/route.ts` | Log content-type/length markers for large chat payloads. Set `"0"` to silence. |
| `DEBUG_RESPONSES_SSE_TO_JSON` | _(unset)_ | `open-sse/handlers/responseTranslator.ts` | Set `true` to log Responses API SSE→JSON translation details. |
| `NEXT_PUBLIC_OMNIROUTE_E2E_MODE` | _(unset)_ | E2E test harness | Set `true` to enable E2E test mode (relaxed auth, test hooks). |
@@ -794,27 +794,27 @@ Provider quota endpoints, network tunnels (Tailscale, Ngrok, MITM debug proxy),
## 26. Test & E2E Harness
Used by `scripts/run-next-playwright.mjs`, `scripts/smoke-electron-packaged.mjs`,
`scripts/run-ecosystem-tests.mjs`, and `scripts/uninstall.mjs`. Leave every
Used by `scripts/dev/run-next-playwright.mjs`, `scripts/dev/smoke-electron-packaged.mjs`,
`scripts/dev/run-ecosystem-tests.mjs`, and `scripts/build/uninstall.mjs`. Leave every
value below unset in production deployments.
| Variable | Default | Source File | Description |
| ------------------------------------- | -------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------- |
| `OMNIROUTE_E2E_BOOTSTRAP_MODE` | `auth` | `scripts/run-next-playwright.mjs` | E2E bootstrap mode (`auth`, `fresh`, `reuse`) for the Playwright runner. |
| `OMNIROUTE_E2E_PASSWORD` | falls back to `INITIAL_PASSWORD` | `scripts/run-next-playwright.mjs` | Admin password injected into the Playwright environment. |
| `OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK` | `true` | `scripts/run-next-playwright.mjs` | Disable the local healthcheck poll during Playwright runs. |
| `OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK` | `true` | `scripts/run-next-playwright.mjs` | Disable the OAuth token healthcheck loop during tests. |
| `OMNIROUTE_HIDE_HEALTHCHECK_LOGS` | `true` | `scripts/run-next-playwright.mjs` | Silence healthcheck noise in Playwright stdout. |
| `OMNIROUTE_PLAYWRIGHT_SKIP_BUILD` | `0` | `scripts/run-next-playwright.mjs` | Skip the Next.js production build before Playwright starts (CI optimization). |
| `OMNIROUTE_SKIP_UNINSTALL_HOOK` | `0` | `scripts/uninstall.mjs` | Skip the OmniRoute uninstall hook (used by CI to keep `node_modules` intact). |
| `ECOSYSTEM_SERVER_WAIT_MS` | `180000` | `scripts/run-ecosystem-tests.mjs` | Wait time (ms) for the server to become healthy before running ecosystem/protocol tests. |
| `ELECTRON_SMOKE_URL` | `http://127.0.0.1:20128/login` | `scripts/smoke-electron-packaged.mjs` | URL the Electron smoke harness expects the packaged app to serve. |
| `ELECTRON_SMOKE_TIMEOUT_MS` | `45000` | `scripts/smoke-electron-packaged.mjs` | Total timeout (ms) before the smoke harness gives up. |
| `ELECTRON_SMOKE_SETTLE_MS` | `2000` | `scripts/smoke-electron-packaged.mjs` | Settle window (ms) after the page loads. |
| `ELECTRON_SMOKE_APP_EXECUTABLE` | _(auto)_ | `scripts/smoke-electron-packaged.mjs` | Explicit path to the packaged Electron executable. |
| `ELECTRON_SMOKE_DATA_DIR` | _(tmpdir)_ | `scripts/smoke-electron-packaged.mjs` | Data directory for the Electron smoke run. |
| `ELECTRON_SMOKE_KEEP_DATA` | `0` | `scripts/smoke-electron-packaged.mjs` | Set `1` to preserve the smoke data directory after the run. |
| `ELECTRON_SMOKE_STREAM_LOGS` | `0` | `scripts/smoke-electron-packaged.mjs` | Set `1` to stream Electron logs to stdout during the run. |
| ------------------------------------- | -------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- |
| `OMNIROUTE_E2E_BOOTSTRAP_MODE` | `auth` | `scripts/dev/run-next-playwright.mjs` | E2E bootstrap mode (`auth`, `fresh`, `reuse`) for the Playwright runner. |
| `OMNIROUTE_E2E_PASSWORD` | falls back to `INITIAL_PASSWORD` | `scripts/dev/run-next-playwright.mjs` | Admin password injected into the Playwright environment. |
| `OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK` | `true` | `scripts/dev/run-next-playwright.mjs` | Disable the local healthcheck poll during Playwright runs. |
| `OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK` | `true` | `scripts/dev/run-next-playwright.mjs` | Disable the OAuth token healthcheck loop during tests. |
| `OMNIROUTE_HIDE_HEALTHCHECK_LOGS` | `true` | `scripts/dev/run-next-playwright.mjs` | Silence healthcheck noise in Playwright stdout. |
| `OMNIROUTE_PLAYWRIGHT_SKIP_BUILD` | `0` | `scripts/dev/run-next-playwright.mjs` | Skip the Next.js production build before Playwright starts (CI optimization). |
| `OMNIROUTE_SKIP_UNINSTALL_HOOK` | `0` | `scripts/build/uninstall.mjs` | Skip the OmniRoute uninstall hook (used by CI to keep `node_modules` intact). |
| `ECOSYSTEM_SERVER_WAIT_MS` | `180000` | `scripts/dev/run-ecosystem-tests.mjs` | Wait time (ms) for the server to become healthy before running ecosystem/protocol tests. |
| `ELECTRON_SMOKE_URL` | `http://127.0.0.1:20128/login` | `scripts/dev/smoke-electron-packaged.mjs` | URL the Electron smoke harness expects the packaged app to serve. |
| `ELECTRON_SMOKE_TIMEOUT_MS` | `45000` | `scripts/dev/smoke-electron-packaged.mjs` | Total timeout (ms) before the smoke harness gives up. |
| `ELECTRON_SMOKE_SETTLE_MS` | `2000` | `scripts/dev/smoke-electron-packaged.mjs` | Settle window (ms) after the page loads. |
| `ELECTRON_SMOKE_APP_EXECUTABLE` | _(auto)_ | `scripts/dev/smoke-electron-packaged.mjs` | Explicit path to the packaged Electron executable. |
| `ELECTRON_SMOKE_DATA_DIR` | _(tmpdir)_ | `scripts/dev/smoke-electron-packaged.mjs` | Data directory for the Electron smoke run. |
| `ELECTRON_SMOKE_KEEP_DATA` | `0` | `scripts/dev/smoke-electron-packaged.mjs` | Set `1` to preserve the smoke data directory after the run. |
| `ELECTRON_SMOKE_STREAM_LOGS` | `0` | `scripts/dev/smoke-electron-packaged.mjs` | Set `1` to stream Electron logs to stdout during the run. |
| `CLI_DEVIN_BIN` | _(PATH lookup)_ | `open-sse/executors/devin-cli.ts` | Override the Devin CLI binary path. |
### Docs translation pipeline

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@
"pack": "npm run prepare:bundle && electron-builder --dir"
},
"dependencies": {
"better-sqlite3": "^12.9.0",
"better-sqlite3": "^12.10.0",
"electron-updater": "^6.8.5"
},
"devDependencies": {
@@ -33,7 +33,6 @@
"electron-builder": "^26.10.0"
},
"overrides": {
"@xmldom/xmldom": "^0.9.10",
"plist": "^4.0.0"
},
"build": {

View File

@@ -142,7 +142,7 @@ function clampMaxTokens(value: unknown): number {
return Math.max(1, Math.min(Math.floor(numeric), MAX_COMMAND_CODE_TOKENS));
}
function buildCommandCodeBody(model: string, body: unknown): JsonRecord {
function buildCommandCodeBody(model: string, body: unknown, stream: boolean): JsonRecord {
const input = isRecord(body) ? body : {};
const converted = convertMessages(input.messages);
const explicitSystem = typeof input.system === "string" ? input.system : "";
@@ -169,7 +169,7 @@ function buildCommandCodeBody(model: string, body: unknown): JsonRecord {
tools: convertTools(input.tools),
system,
max_tokens: clampMaxTokens(input.max_tokens ?? input.max_completion_tokens),
stream: false,
stream,
},
};
}
@@ -512,7 +512,7 @@ export class CommandCodeExecutor extends BaseExecutor {
};
mergeUpstreamExtraHeaders(headers, upstreamExtraHeaders);
const transformedBody = buildCommandCodeBody(model, body);
const transformedBody = buildCommandCodeBody(model, body, stream);
const url = this.buildUrl();
const upstream = await fetch(url, {
method: "POST",

169
package-lock.json generated
View File

@@ -18,9 +18,9 @@
"@monaco-editor/react": "^4.7.0",
"@ngrok/ngrok": "^1.7.0",
"@swc/helpers": "0.5.21",
"axios": "^1.16.0",
"axios": "^1.16.1",
"bcryptjs": "^3.0.3",
"better-sqlite3": "^12.9.0",
"better-sqlite3": "^12.10.0",
"bottleneck": "^2.19.5",
"express": "^5.2.1",
"fetch-socks": "^1.3.3",
@@ -29,17 +29,17 @@
"http-proxy-middleware": "^4.0.0",
"https-proxy-agent": "^9.0.0",
"ioredis": "^5.10.1",
"isomorphic-dompurify": "^3.12.0",
"isomorphic-dompurify": "^3.13.0",
"jose": "^6.2.3",
"js-yaml": "^4.1.1",
"jsonc-parser": "^3.3.1",
"lowdb": "^7.0.1",
"lucide-react": "^1.14.0",
"lucide-react": "^1.16.0",
"marked": "^18.0.3",
"mermaid": "^11.14.0",
"mermaid": "^11.15.0",
"monaco-editor": "^0.55.1",
"next": "^16.2.6",
"next-intl": "^4.11.1",
"next-intl": "^4.12.0",
"node-machine-id": "^1.1.12",
"open": "^11.0.0",
"ora": "^9.4.0",
@@ -53,7 +53,7 @@
"recharts": "^3.8.1",
"selfsigned": "^5.5.0",
"tls-client-node": "^0.1.13",
"tsx": "^4.21.0",
"tsx": "^4.21.1",
"undici": "^8.2.0",
"uuid": "^14.0.0",
"wreq-js": "^2.3.0",
@@ -67,14 +67,14 @@
"omniroute-reset-password": "bin/reset-password.mjs"
},
"devDependencies": {
"@playwright/test": "^1.59.1",
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4.3.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/bcryptjs": "^3.0.0",
"@types/better-sqlite3": "^7.6.13",
"@types/keytar": "^4.4.2",
"@types/node": "^25.6.2",
"@types/node": "^25.7.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
@@ -91,9 +91,9 @@
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2",
"vitest": "^4.1.5",
"wait-on": "^9.0.5",
"typescript-eslint": "^8.59.3",
"vitest": "^4.1.6",
"wait-on": "^9.0.10",
"wtfnode": "^0.10.1"
},
"engines": {
@@ -1430,18 +1430,18 @@
"license": "MIT"
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "3.5.7",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.7.tgz",
"integrity": "sha512-wJxRZ+SiUCIMTL86bQlZU9bEKDQqqvgk2ezQ1BySUdWRfHqOzj4IKUVFeUZKS9w58M4e7wMSG0Sl86LAPb7Qww==",
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.8.tgz",
"integrity": "sha512-uZLvzLFN7iV2l8cbDdROwgKGtdELeLI4bpnsuz1DnyscHDxn8TdDE0anHzcfjtWK66XYCllGLV3Mi3CYcEPg/g==",
"license": "MIT",
"dependencies": {
"@formatjs/icu-skeleton-parser": "2.1.7"
"@formatjs/icu-skeleton-parser": "2.1.8"
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.7.tgz",
"integrity": "sha512-cIw1SFP0bi0CUBiJ2jzp99ws3OJNQDfStcHq9Z0iHWzItmiIikihFO+npR8C80yDlp7ZuBCLXCcKjgWjHicksA==",
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.8.tgz",
"integrity": "sha512-iX5i0O15gPf69l1WqmLFYwn7wq53lauvytvWFnHamIfX/5Ta56gpFj6fdeHRcKTV58IhrKv8QOvWfTYZYm7f+g==",
"license": "MIT"
},
"node_modules/@formatjs/intl-localematcher": {
@@ -5626,16 +5626,42 @@
}
},
"node_modules/axios": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
"integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
},
"node_modules/axios/node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/axios/node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -5720,9 +5746,9 @@
}
},
"node_modules/better-sqlite3": {
"version": "12.9.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.9.0.tgz",
"integrity": "sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==",
"version": "12.10.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
"integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -5730,7 +5756,7 @@
"prebuild-install": "^7.1.1"
},
"engines": {
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
"node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x"
}
},
"node_modules/bidi-js": {
@@ -7358,9 +7384,9 @@
}
},
"node_modules/dompurify": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz",
"integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==",
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.3.tgz",
"integrity": "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
@@ -8895,6 +8921,7 @@
"version": "4.13.7",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz",
"integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
@@ -9366,9 +9393,9 @@
}
},
"node_modules/icu-minify": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.11.1.tgz",
"integrity": "sha512-C0tsPVuvyNp+++qWJP+mty/KLLStjerOZqu3W1xWLJkChEDbDi9Taoj6blK7L/onxbuVzwgH6k9Sf+rOV6lOvw==",
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.12.0.tgz",
"integrity": "sha512-zDmM05uav3t3+kxSfRrNlmyXOdj2b+uHA+p04CG32eJabtaHbugXujuL+YfRkwP9joAnf0Uh+RMGCKD5NLa5rQ==",
"funding": [
{
"type": "individual",
@@ -9499,19 +9526,19 @@
}
},
"node_modules/intl-messageformat": {
"version": "11.2.4",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.4.tgz",
"integrity": "sha512-iKP6+uJXn+XcfRgYfGPE3+mqCoODV2vATrXDLo/YkYgIdelJHJPBEbc0GZThipAYPuk+8QJFiPgOfblU085ABg==",
"version": "11.2.5",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.5.tgz",
"integrity": "sha512-zaROHiUsnlSFXVypU54AsQuAm3DLmmSH8KfDhiUuG1XZ9NTQ4o3xlxIJYVNmeWAklyp3CWg0lhexNUnee8PsYQ==",
"license": "BSD-3-Clause",
"dependencies": {
"@formatjs/fast-memoize": "3.1.4",
"@formatjs/icu-messageformat-parser": "3.5.7"
"@formatjs/fast-memoize": "3.1.5",
"@formatjs/icu-messageformat-parser": "3.5.8"
}
},
"node_modules/intl-messageformat/node_modules/@formatjs/fast-memoize": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.4.tgz",
"integrity": "sha512-Lbke1aOrsygKKR09Ux0NrZgbTqpDmiwXOgzyDOJ8Owr1zd5qOKTauf62hH+Seeku3ju77rHWH9I5SfX2CN0vuA==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.5.tgz",
"integrity": "sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A==",
"license": "MIT"
},
"node_modules/ioredis": {
@@ -9539,9 +9566,9 @@
}
},
"node_modules/ip-address": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.1.tgz",
"integrity": "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==",
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -10170,12 +10197,12 @@
"license": "ISC"
},
"node_modules/isomorphic-dompurify": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-3.12.0.tgz",
"integrity": "sha512-8n+j+6ypTHvriJwFOQ2qusQ6bzGjZVcR3jbe1pBpLcGI1dn4WIl0ctLBngqE5QttquQBAlKXwJeTMw+X7x7qKw==",
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-3.13.0.tgz",
"integrity": "sha512-QzgzjAGJN0QoOpLWx7mkMhhTQvQXsBpS6oEi2Wy58mEWwrvaRJrx5hrVEdsM70nNKOwHCHj3bwYkwI+HFd3Khg==",
"license": "MIT",
"dependencies": {
"dompurify": "^3.4.2",
"dompurify": "^3.4.3",
"jsdom": "^29.1.1"
},
"engines": {
@@ -11088,9 +11115,9 @@
}
},
"node_modules/lucide-react": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.14.0.tgz",
"integrity": "sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.16.0.tgz",
"integrity": "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -12101,9 +12128,9 @@
}
},
"node_modules/next-intl": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.11.1.tgz",
"integrity": "sha512-s32lFFLXkxrW6fy+4IVaGD5J8xPpbEDFLfBbXV73CTbHAGhOGMjYN4/rftdsKOQ44AnPhnZ5Et+ZNMr5tRpsqA==",
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.12.0.tgz",
"integrity": "sha512-v8KpppWG0yLLlChJ3Of6uoPew9LeRDBAtY6vpJmF7YJmBZlHEzzoEL4w1g1dAU+VleEPNoXNm9hg1eEsKWV5hw==",
"funding": [
{
"type": "individual",
@@ -12115,11 +12142,11 @@
"@formatjs/intl-localematcher": "^0.8.1",
"@parcel/watcher": "^2.4.1",
"@swc/core": "^1.15.2",
"icu-minify": "^4.11.1",
"icu-minify": "^4.12.0",
"negotiator": "^1.0.0",
"next-intl-swc-plugin-extractor": "^4.11.1",
"next-intl-swc-plugin-extractor": "^4.12.0",
"po-parser": "^2.1.1",
"use-intl": "^4.11.1"
"use-intl": "^4.12.0"
},
"peerDependencies": {
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -12132,9 +12159,9 @@
}
},
"node_modules/next-intl-swc-plugin-extractor": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.11.1.tgz",
"integrity": "sha512-jHKGij7NoYccy2y54+e/wHVMoRgNt4h/Kn0XS9c4GbKu3KgJyANLUN8sFcDixv6sqz4V2kh6CTWgrkIidQksUg==",
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.12.0.tgz",
"integrity": "sha512-jUxVEu1Nryjt4YgaDktSys7ioOgQfcNPF/SF2dbPNxbVb6U+P1INRgHeCVN+EC59H2rnTFIQwbddmOCrUWFr3g==",
"license": "MIT"
},
"node_modules/next/node_modules/@swc/helpers": {
@@ -12910,9 +12937,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.10",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
"version": "8.5.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
"funding": [
{
"type": "opencollective",
@@ -13527,6 +13554,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
@@ -15003,13 +15031,12 @@
"license": "0BSD"
},
"node_modules/tsx": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.1.tgz",
"integrity": "sha512-5QE2Q04cN1u0993w0LT5rPw3faZqZU1fFn1mGE0pV53N1Dn7c+QFFxQu1mBeSgeOXwFyTicZw02wVgp3Tb5cAQ==",
"license": "MIT",
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
"esbuild": "~0.27.0"
},
"bin": {
"tsx": "dist/cli.mjs"
@@ -15422,9 +15449,9 @@
}
},
"node_modules/use-intl": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.11.1.tgz",
"integrity": "sha512-/dqWSqUSbVMzC+fdy7io8enhGYHeGeHK1bFhTLrp0ZblqdzY4FkE+tkffW6IfCauqaIA2/z4DQae4XEn93+raw==",
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.12.0.tgz",
"integrity": "sha512-r+qVb7UI1+kiOhjYsmsNUCY+jrnjVopwGeFlmMyQj4YInlwZzgMeMSv9n8MqnWWy77HL5BVM8K2WgX50SbtcpA==",
"funding": [
{
"type": "individual",
@@ -15435,7 +15462,7 @@
"dependencies": {
"@formatjs/fast-memoize": "^3.1.0",
"@schummar/icu-type-parser": "1.21.5",
"icu-minify": "^4.11.1",
"icu-minify": "^4.12.0",
"intl-messageformat": "^11.1.0"
},
"peerDependencies": {

View File

@@ -65,9 +65,9 @@
"scripts": {
"dev": "node scripts/dev/run-next.mjs dev",
"prebuild:docs": "node scripts/docs/generate-docs-index.mjs && node scripts/docs/gen-openapi-module.mjs",
"gen:provider-reference": "node --import tsx/esm scripts/docs/gen-provider-reference.ts",
"gen:provider-reference": "node --import tsx scripts/docs/gen-provider-reference.ts",
"build": "node scripts/build/build-next-isolated.mjs",
"build:cli": "node --import tsx/esm scripts/build/prepublish.ts",
"build:cli": "node --import tsx scripts/build/prepublish.ts",
"start": "node scripts/dev/run-next.mjs start",
"lint": "eslint .",
"electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:20128 && cd electron && npm run dev\"",
@@ -76,11 +76,11 @@
"electron:build:mac": "npm run build && cd electron && npm run build:mac",
"electron:build:linux": "npm run build && cd electron && npm run build:linux",
"electron:smoke:packaged": "node scripts/dev/smoke-electron-packaged.mjs",
"test": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test --test-concurrency=10 tests/unit/*.test.ts",
"test:unit": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test --test-concurrency=10 tests/unit/*.test.ts",
"test:plan3": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/plan3-p0.test.ts",
"test:fixes": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/fixes-p1.test.ts",
"test:security": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/security-fase01.test.ts",
"test": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test --test-concurrency=10 tests/unit/*.test.ts",
"test:unit": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test --test-concurrency=10 tests/unit/*.test.ts",
"test:plan3": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/plan3-p0.test.ts",
"test:fixes": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/fixes-p1.test.ts",
"test:security": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/security-fase01.test.ts",
"check:cycles": "node scripts/check/check-cycles.mjs",
"check:route-validation:t06": "node scripts/check/check-route-validation.mjs",
"check:any-budget:t11": "node scripts/check/check-t11-any-budget.mjs",
@@ -97,21 +97,21 @@
"i18n:sync-ui": "node scripts/i18n/sync-ui-keys.mjs",
"i18n:sync-ui:dry": "node scripts/i18n/sync-ui-keys.mjs --dry-run",
"i18n:check-ui-coverage": "node scripts/i18n/check-ui-keys-coverage.mjs",
"check:node-runtime": "node --import tsx/esm scripts/check/check-supported-node-runtime.ts",
"check:pack-artifact": "node --import tsx/esm scripts/build/validate-pack-artifact.ts",
"check:node-runtime": "node --import tsx scripts/check/check-supported-node-runtime.ts",
"check:pack-artifact": "node --import tsx scripts/build/validate-pack-artifact.ts",
"audit:deps": "npm audit --audit-level=moderate && npm run audit:electron",
"audit:electron": "npm --prefix electron audit --audit-level=moderate",
"typecheck:core": "tsc --pretty false -p tsconfig.typecheck-core.json",
"typecheck:noimplicit:core": "tsc --pretty false -p tsconfig.typecheck-noimplicit-core.json",
"backfill-aggregation": "node --import tsx/esm src/scripts/backfillAggregation.ts",
"backfill-aggregation": "node --import tsx src/scripts/backfillAggregation.ts",
"env:sync": "node scripts/dev/sync-env.mjs",
"test:integration": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test --test-force-exit --test-concurrency=1 tests/integration/*.test.ts",
"test:integration": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test --test-force-exit --test-concurrency=1 tests/integration/*.test.ts",
"test:e2e": "node scripts/dev/run-playwright-tests.mjs test tests/e2e/*.spec.ts",
"test:protocols:e2e": "node scripts/dev/run-protocol-clients-tests.mjs",
"test:vitest": "vitest run --config vitest.mcp.config.ts",
"test:ecosystem": "node scripts/dev/run-ecosystem-tests.mjs",
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 75 --lines 75 --functions 75 --branches 70 node --import tsx/esm --test --test-concurrency=1 tests/unit/*.test.ts",
"test:coverage:legacy": "c8 --output-dir coverage --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx/esm --test tests/unit/*.test.ts",
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 75 --lines 75 --functions 75 --branches 70 node --import tsx --test --test-concurrency=1 tests/unit/*.test.ts",
"test:coverage:legacy": "c8 --output-dir coverage --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx --test tests/unit/*.test.ts",
"coverage:report": "c8 report --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov",
"coverage:summary": "node scripts/check/test-report-summary.mjs --input coverage/coverage-summary.json --output coverage/coverage-report.md --threshold 60",
"check:pr-test-policy": "node scripts/check/check-pr-test-policy.mjs",
@@ -131,9 +131,9 @@
"@monaco-editor/react": "^4.7.0",
"@ngrok/ngrok": "^1.7.0",
"@swc/helpers": "0.5.21",
"axios": "^1.16.0",
"axios": "^1.16.1",
"bcryptjs": "^3.0.3",
"better-sqlite3": "^12.9.0",
"better-sqlite3": "^12.10.0",
"bottleneck": "^2.19.5",
"express": "^5.2.1",
"fetch-socks": "^1.3.3",
@@ -142,17 +142,17 @@
"http-proxy-middleware": "^4.0.0",
"https-proxy-agent": "^9.0.0",
"ioredis": "^5.10.1",
"isomorphic-dompurify": "^3.12.0",
"isomorphic-dompurify": "^3.13.0",
"jose": "^6.2.3",
"js-yaml": "^4.1.1",
"jsonc-parser": "^3.3.1",
"lowdb": "^7.0.1",
"lucide-react": "^1.14.0",
"lucide-react": "^1.16.0",
"marked": "^18.0.3",
"mermaid": "^11.14.0",
"mermaid": "^11.15.0",
"monaco-editor": "^0.55.1",
"next": "^16.2.6",
"next-intl": "^4.11.1",
"next-intl": "^4.12.0",
"node-machine-id": "^1.1.12",
"open": "^11.0.0",
"ora": "^9.4.0",
@@ -166,7 +166,7 @@
"recharts": "^3.8.1",
"selfsigned": "^5.5.0",
"tls-client-node": "^0.1.13",
"tsx": "^4.21.0",
"tsx": "^4.21.1",
"undici": "^8.2.0",
"uuid": "^14.0.0",
"wreq-js": "^2.3.0",
@@ -179,14 +179,14 @@
"keytar": "^7.9.0"
},
"devDependencies": {
"@playwright/test": "^1.59.1",
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4.3.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/bcryptjs": "^3.0.0",
"@types/better-sqlite3": "^7.6.13",
"@types/keytar": "^4.4.2",
"@types/node": "^25.6.2",
"@types/node": "^25.7.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
@@ -203,9 +203,9 @@
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2",
"vitest": "^4.1.5",
"wait-on": "^9.0.5",
"typescript-eslint": "^8.59.3",
"vitest": "^4.1.6",
"wait-on": "^9.0.10",
"wtfnode": "^0.10.1"
},
"lint-staged": {
@@ -228,14 +228,8 @@
]
},
"overrides": {
"lodash-es": "^4.18.1",
"dompurify": "^3.4.2",
"path-to-regexp": "^8.4.0",
"postcss": "^8.5.10",
"ip-address": "10.1.1",
"hono": "^4.12.18",
"@hono/node-server": "^1.19.13",
"react": "$react",
"react-dom": "$react-dom"
"dompurify": "^3.4.3",
"postcss": "^8.5.14",
"ip-address": "10.2.0"
}
}

View File

@@ -22,13 +22,13 @@
"src/shared/contracts/",
"src/shared/utils/nodeRuntimeSupport.ts",
".env.example",
"scripts/postinstall.mjs",
"scripts/postinstallSupport.mjs",
"scripts/responses-ws-proxy.mjs",
"scripts/check-supported-node-runtime.ts",
"scripts/sync-env.mjs",
"scripts/native-binary-compat.mjs",
"scripts/build-next-isolated.mjs",
"scripts/build/postinstall.mjs",
"scripts/build/postinstallSupport.mjs",
"scripts/dev/responses-ws-proxy.mjs",
"scripts/check/check-supported-node-runtime.ts",
"scripts/dev/sync-env.mjs",
"scripts/build/native-binary-compat.mjs",
"scripts/build/build-next-isolated.mjs",
"README.md",
"LICENSE"
],
@@ -61,54 +61,54 @@
},
"homepage": "https://omniroute.online",
"scripts": {
"dev": "node scripts/run-next.mjs dev",
"prebuild:docs": "node scripts/generate-docs-index.mjs",
"build": "node scripts/build-next-isolated.mjs",
"build:cli": "node --import tsx/esm scripts/prepublish.ts",
"start": "node scripts/run-next.mjs start",
"dev": "node scripts/dev/run-next.mjs dev",
"prebuild:docs": "node scripts/docs/generate-docs-index.mjs",
"build": "node scripts/build/build-next-isolated.mjs",
"build:cli": "node --import tsx scripts/build/prepublish.ts",
"start": "node scripts/dev/run-next.mjs start",
"lint": "eslint .",
"electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:20128 && cd electron && npm run dev\"",
"electron:build": "npm run build && cd electron && npm run build",
"electron:build:win": "npm run build && cd electron && npm run build:win",
"electron:build:mac": "npm run build && cd electron && npm run build:mac",
"electron:build:linux": "npm run build && cd electron && npm run build:linux",
"electron:smoke:packaged": "node scripts/smoke-electron-packaged.mjs",
"test": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test --test-concurrency=10 tests/unit/*.test.ts",
"test:unit": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test --test-concurrency=10 tests/unit/*.test.ts",
"test:plan3": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/plan3-p0.test.ts",
"test:fixes": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/fixes-p1.test.ts",
"test:security": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --test tests/unit/security-fase01.test.ts",
"check:cycles": "node scripts/check-cycles.mjs",
"check:route-validation:t06": "node scripts/check-route-validation.mjs",
"check:any-budget:t11": "node scripts/check-t11-any-budget.mjs",
"check:docs-sync": "node scripts/check-docs-sync.mjs",
"check:node-runtime": "node --import tsx/esm scripts/check-supported-node-runtime.ts",
"check:pack-artifact": "node --import tsx/esm scripts/validate-pack-artifact.ts",
"electron:smoke:packaged": "node scripts/dev/smoke-electron-packaged.mjs",
"test": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test --test-concurrency=10 tests/unit/*.test.ts",
"test:unit": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test --test-concurrency=10 tests/unit/*.test.ts",
"test:plan3": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/plan3-p0.test.ts",
"test:fixes": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/fixes-p1.test.ts",
"test:security": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --test tests/unit/security-fase01.test.ts",
"check:cycles": "node scripts/check/check-cycles.mjs",
"check:route-validation:t06": "node scripts/check/check-route-validation.mjs",
"check:any-budget:t11": "node scripts/check/check-t11-any-budget.mjs",
"check:docs-sync": "node scripts/check/check-docs-sync.mjs",
"check:node-runtime": "node --import tsx scripts/check/check-supported-node-runtime.ts",
"check:pack-artifact": "node --import tsx scripts/build/validate-pack-artifact.ts",
"audit:deps": "npm audit --audit-level=moderate && npm run audit:electron",
"audit:electron": "npm --prefix electron audit --audit-level=moderate",
"typecheck:core": "tsc --pretty false -p tsconfig.typecheck-core.json",
"typecheck:noimplicit:core": "tsc --pretty false -p tsconfig.typecheck-noimplicit-core.json",
"backfill-aggregation": "node --import tsx/esm src/scripts/backfillAggregation.ts",
"env:sync": "node scripts/sync-env.mjs",
"test:integration": "node --import tsx/esm --test tests/integration/*.test.ts",
"test:e2e": "node scripts/run-playwright-tests.mjs test tests/e2e/*.spec.ts",
"test:protocols:e2e": "node scripts/run-protocol-clients-tests.mjs",
"backfill-aggregation": "node --import tsx src/scripts/backfillAggregation.ts",
"env:sync": "node scripts/dev/sync-env.mjs",
"test:integration": "node --import tsx --test tests/integration/*.test.ts",
"test:e2e": "node scripts/dev/run-playwright-tests.mjs test tests/e2e/*.spec.ts",
"test:protocols:e2e": "node scripts/dev/run-protocol-clients-tests.mjs",
"test:vitest": "vitest run --config vitest.mcp.config.ts",
"test:ecosystem": "node scripts/run-ecosystem-tests.mjs",
"test:coverage": "c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 60 --lines 60 --functions 60 --branches 60 node --import tsx/esm --test --test-concurrency=10 tests/unit/*.test.ts",
"test:coverage:legacy": "c8 --output-dir coverage --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx/esm --test tests/unit/*.test.ts",
"test:ecosystem": "node scripts/dev/run-ecosystem-tests.mjs",
"test:coverage": "c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 60 --lines 60 --functions 60 --branches 60 node --import tsx --test --test-concurrency=10 tests/unit/*.test.ts",
"test:coverage:legacy": "c8 --output-dir coverage --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx --test tests/unit/*.test.ts",
"coverage:report": "c8 report --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov",
"coverage:summary": "node scripts/test-report-summary.mjs --input coverage/coverage-summary.json --output coverage/coverage-report.md --threshold 60",
"check:pr-test-policy": "node scripts/check-pr-test-policy.mjs",
"coverage:summary": "node scripts/check/test-report-summary.mjs --input coverage/coverage-summary.json --output coverage/coverage-report.md --threshold 60",
"check:pr-test-policy": "node scripts/check/check-pr-test-policy.mjs",
"coverage:report:legacy": "c8 report --output-dir coverage --exclude=open-sse --reporter=text --reporter=text-summary",
"test:all": "npm run test:unit && npm run test:vitest && npm run test:ecosystem && npm run test:e2e",
"check": "npm run lint && npm run test",
"prepublishOnly": "npm run build:cli && npm run check:pack-artifact",
"postinstall": "node scripts/postinstall.mjs",
"uninstall": "node scripts/uninstall.mjs",
"uninstall:full": "node scripts/uninstall.mjs --full",
"postinstall": "node scripts/build/postinstall.mjs",
"uninstall": "node scripts/build/uninstall.mjs",
"uninstall:full": "node scripts/build/uninstall.mjs --full",
"prepare": "husky",
"system-info": "node scripts/system-info.mjs"
"system-info": "node scripts/dev/system-info.mjs"
},
"dependencies": {
"@lobehub/icons": "^5.8.0",
@@ -116,26 +116,26 @@
"@monaco-editor/react": "^4.7.0",
"@ngrok/ngrok": "^1.7.0",
"@swc/helpers": "0.5.21",
"axios": "^1.16.0",
"axios": "^1.16.1",
"bcryptjs": "^3.0.3",
"better-sqlite3": "^12.9.0",
"better-sqlite3": "^12.10.0",
"bottleneck": "^2.19.5",
"express": "^5.2.1",
"fetch-socks": "^1.3.3",
"fuse.js": "^7.3.0",
"http-proxy-middleware": "^3.0.5",
"https-proxy-agent": "^9.0.0",
"isomorphic-dompurify": "^3.12.0",
"isomorphic-dompurify": "^3.13.0",
"jose": "^6.2.3",
"js-yaml": "^4.1.1",
"jsonc-parser": "^3.3.1",
"lowdb": "^7.0.1",
"lucide-react": "^1.14.0",
"lucide-react": "^1.16.0",
"marked": "^18.0.3",
"mermaid": "^11.14.0",
"mermaid": "^11.15.0",
"monaco-editor": "^0.55.1",
"next": "^16.2.6",
"next-intl": "^4.11.1",
"next-intl": "^4.12.0",
"node-machine-id": "^1.1.12",
"open": "^11.0.0",
"ora": "^9.4.0",
@@ -149,7 +149,7 @@
"recharts": "^3.8.1",
"selfsigned": "^5.5.0",
"tls-client-node": "^0.1.13",
"tsx": "^4.21.0",
"tsx": "^4.21.1",
"undici": "^8.2.0",
"uuid": "^14.0.0",
"wreq-js": "^2.3.0",
@@ -162,14 +162,14 @@
"keytar": "^7.9.0"
},
"devDependencies": {
"@playwright/test": "^1.59.1",
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4.3.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/bcryptjs": "^3.0.0",
"@types/better-sqlite3": "^7.6.13",
"@types/keytar": "^4.4.2",
"@types/node": "^25.6.2",
"@types/node": "^25.7.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
@@ -187,9 +187,9 @@
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2",
"vitest": "^4.1.5",
"wait-on": "^9.0.5",
"typescript-eslint": "^8.59.3",
"vitest": "^4.1.6",
"wait-on": "^9.0.10",
"wtfnode": "^0.10.1"
},
"lint-staged": {
@@ -212,14 +212,8 @@
]
},
"overrides": {
"lodash-es": "^4.18.1",
"dompurify": "^3.4.2",
"path-to-regexp": "^8.4.0",
"postcss": "^8.5.10",
"ip-address": "10.1.1",
"hono": "^4.12.18",
"@hono/node-server": "^1.19.13",
"react": "$react",
"react-dom": "$react-dom"
"dompurify": "^3.4.3",
"postcss": "^8.5.14",
"ip-address": "10.2.0"
}
}

View File

@@ -3,13 +3,13 @@
* cursor-tap — capture cursor agent.v1.AgentService/Run wire bytes for tests.
*
* Usage:
* CURSOR_TOKEN=... node scripts/cursor-tap.cjs <fixture-name> <prompt>
* CURSOR_TOKEN=... node scripts/ad-hoc/cursor-tap.cjs <fixture-name> <prompt>
*
* Examples:
* node scripts/cursor-tap.cjs single-turn-chat "say only PING"
* node scripts/cursor-tap.cjs system-prompt "be brief|hi" # split on first '|'
* node scripts/cursor-tap.cjs tool-call "weather in Paris" --tools=get_weather
* node scripts/cursor-tap.cjs composer-2-fast "hi" --model=composer-2-fast
* node scripts/ad-hoc/cursor-tap.cjs single-turn-chat "say only PING"
* node scripts/ad-hoc/cursor-tap.cjs system-prompt "be brief|hi" # split on first '|'
* node scripts/ad-hoc/cursor-tap.cjs tool-call "weather in Paris" --tools=get_weather
* node scripts/ad-hoc/cursor-tap.cjs composer-2-fast "hi" --model=composer-2-fast
*
* Writes the upstream response bytes to tests/fixtures/cursor/<fixture-name>.bin
* and prints decoded summary to stdout. Use these fixtures in unit tests to
@@ -27,7 +27,9 @@ const crypto = require("crypto");
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: cursor-tap.cjs <fixture-name> <prompt> [--model=...] [--tools=name1,name2]");
console.error(
"Usage: cursor-tap.cjs <fixture-name> <prompt> [--model=...] [--tools=name1,name2]"
);
process.exit(1);
}

View File

@@ -64,7 +64,7 @@ async function main() {
};
if (!(await isServerReady())) {
serverProcess = spawn(process.execPath, ["scripts/run-next-playwright.mjs", "dev"], {
serverProcess = spawn(process.execPath, ["scripts/dev/run-next-playwright.mjs", "dev"], {
stdio: "inherit",
env: testEnv,
});

View File

@@ -24,7 +24,7 @@ const backupDir = resolvePlaywrightAppBackupDir({
appDirExists: existsSync(appDir),
});
const usingAlternativeBackupDir = backupDir !== defaultBackupDir;
const buildScript = join(cwd, "scripts", "build-next-isolated.mjs");
const buildScript = join(cwd, "scripts", "build", "build-next-isolated.mjs");
const standaloneServer = join(cwd, testDistDir(), "standalone", "server.js");
const rootStaticDir = join(cwd, testDistDir(), "static");
const rootPublicDir = join(cwd, "public");

View File

@@ -60,7 +60,7 @@ async function main() {
};
if (!(await isServerReady())) {
serverProcess = spawn(process.execPath, ["scripts/run-next-playwright.mjs", "dev"], {
serverProcess = spawn(process.execPath, ["scripts/dev/run-next-playwright.mjs", "dev"], {
stdio: "inherit",
env: testEnv,
});

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
// Generates docs/reference/PROVIDER_REFERENCE.md from src/shared/constants/providers.ts.
// Run: node --import tsx/esm scripts/docs/gen-provider-reference.ts
// Run: node --import tsx scripts/docs/gen-provider-reference.ts
import fs from "node:fs";
import path from "node:path";

View File

@@ -15,6 +15,7 @@
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";
import { format } from "prettier";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -36,6 +37,12 @@ const SECTION_ORDER = [
const SECTION_INDEX = Object.fromEntries(SECTION_ORDER.map((s, i) => [s.title, i + 1]));
async function writeGeneratedFile(content) {
fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true });
const formatted = await format(content, { parser: "typescript", printWidth: 100 });
fs.writeFileSync(OUT_FILE, formatted, "utf8");
}
function extractTitleFromContent(content) {
const match = content.match(/^#\s+(.+)$/m);
if (match) {
@@ -72,10 +79,8 @@ function extractContentPreview(content) {
return stripped.slice(0, 300);
}
function emitEmpty(reason) {
fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true });
fs.writeFileSync(
OUT_FILE,
async function emitEmpty(reason) {
await writeGeneratedFile(
`// AUTO-GENERATED by scripts/docs/generate-docs-index.mjs — DO NOT EDIT MANUALLY
// Regenerate with: node scripts/docs/generate-docs-index.mjs
@@ -104,8 +109,7 @@ export const autoNavSections: AutoGenNavSection[] = [];
export const autoSearchIndex: AutoGenSearchItem[] = [];
export const autoAllSlugs: string[] = [];
`,
"utf8"
`
);
console.warn(`[generate-docs-index] ${reason}; generated empty docs index.`);
}
@@ -119,7 +123,7 @@ if (!fs.existsSync(DOCS_DIR)) {
);
process.exit(0);
}
emitEmpty(`${DOCS_DIR} not found`);
await emitEmpty(`${DOCS_DIR} not found`);
process.exit(0);
}
@@ -168,7 +172,7 @@ for (const { dir, title } of SECTION_ORDER) {
}
if (docs.length === 0) {
emitEmpty("no docs discovered in subfolders");
await emitEmpty("no docs discovered in subfolders");
process.exit(0);
}
@@ -258,5 +262,5 @@ export const autoAllSlugs: string[] = ${JSON.stringify(
)};
`;
fs.writeFileSync(OUT_FILE, output, "utf8");
await writeGeneratedFile(output);
console.log(`✅ Generated ${OUT_FILE} with ${docs.length} docs, ${navSections.length} sections`);

View File

@@ -357,7 +357,7 @@ function ConnectionCooldownCard({
/>
<BooleanField
label="Use upstream retry hints"
description="Usa valores de retry-after/reset do upstream quando disponíveis."
description="Use upstream retry-after/reset values when available."
checked={current.useUpstreamRetryHints}
onChange={(useUpstreamRetryHints) =>
setDraft((prev) => ({
@@ -409,7 +409,7 @@ function ConnectionCooldownCard({
</p>
</div>
<NumberField
label="Máximo de passos de backoff"
label="Max backoff steps"
value={current.maxBackoffSteps}
min={0}
onChange={(maxBackoffSteps) =>
@@ -424,9 +424,9 @@ function ConnectionCooldownCard({
<span className="font-mono text-text-main">{formatMs(current.baseCooldownMs)}</span>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-text-muted">Usar dicas de retry do upstream</span>
<span className="text-text-muted">Use upstream retry hints</span>
<span className="font-mono text-text-main">
{current.useUpstreamRetryHints ? "Sim" : "Não"}
{current.useUpstreamRetryHints ? "Yes" : "No"}
</span>
</div>
<div className="flex items-center justify-between text-sm">
@@ -440,7 +440,7 @@ function ConnectionCooldownCard({
</span>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-text-muted">Máximo de passos de backoff</span>
<span className="text-text-muted">Max backoff steps</span>
<span className="font-mono text-text-main">{current.maxBackoffSteps}</span>
</div>
</>
@@ -455,12 +455,12 @@ function ConnectionCooldownCard({
<div className="space-y-2">
<div className="flex items-center gap-2">
<span className="material-symbols-outlined text-xl text-primary">timer_off</span>
<h2 className="text-lg font-bold">Cooldown de Conexão</h2>
<h2 className="text-lg font-bold">Connection Cooldown</h2>
</div>
<SectionDescription
scope="Conexão individual"
trigger="Quando uma conexão retorna falha transitória no upstream"
effect="Pula temporariamente essa conexão e aumenta backoff em falhas repetidas"
scope="Individual connection"
trigger="When a connection returns a transient upstream failure"
effect="Temporarily skips that connection and increases backoff after repeated failures"
/>
</div>
<ActionRow
@@ -498,13 +498,13 @@ function ConnectionCooldownCard({
</div>
<p className="mb-4 text-sm text-text-muted">
O cooldown base cobre falhas transitórias de conexão. Quando as dicas de retry do upstream
estão ativas, a janela explícita do provedor sobrescreve o cooldown local.
Base cooldown covers transient connection failures. When upstream retry hints are enabled,
the provider&apos;s explicit retry window overrides the local cooldown.
</p>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{renderProfile("oauth", "Provedores OAuth", "lock")}
{renderProfile("apikey", "Provedores API Key", "key")}
{renderProfile("oauth", "OAuth Providers", "lock")}
{renderProfile("apikey", "API Key Providers", "key")}
</div>
</Card>
);

View File

@@ -1,6 +1,13 @@
import path from "node:path";
import os from "node:os";
import { generateClaudeConfig } from "./claude";
import { generateClineConfig } from "./cline";
import { generateCodexConfig } from "./codex";
import { generateContinueConfig } from "./continue";
import { generateKilocodeConfig } from "./kilocode";
import { generateOpencodeConfig } from "./opencode";
export interface GenerateOptions {
baseUrl: string;
apiKey: string;
@@ -37,21 +44,16 @@ const TOOL_CONFIG_PATHS: Record<string, string> = {
continue: path.join(os.homedir(), ".continue", "config.yaml"),
};
async function importGenerator(toolId: string) {
const generators: Record<string, { module: string; export: string }> = {
claude: { module: "./claude.js", export: "generateClaudeConfig" },
codex: { module: "./codex.js", export: "generateCodexConfig" },
opencode: { module: "./opencode.js", export: "generateOpencodeConfig" },
cline: { module: "./cline.js", export: "generateClineConfig" },
kilocode: { module: "./kilocode.js", export: "generateKilocodeConfig" },
continue: { module: "./continue.js", export: "generateContinueConfig" },
};
type ConfigGenerator = (options: GenerateOptions) => string | Promise<string>;
const gen = generators[toolId];
if (!gen) return null;
const mod = await import(gen.module);
return { generate: mod[gen.export] };
}
const GENERATORS: Record<string, ConfigGenerator> = {
claude: generateClaudeConfig,
codex: generateCodexConfig,
opencode: generateOpencodeConfig,
cline: generateClineConfig,
kilocode: generateKilocodeConfig,
continue: generateContinueConfig,
};
export async function generateConfig(
toolId: string,
@@ -70,11 +72,11 @@ export async function generateConfig(
}
try {
const mod = await importGenerator(toolId);
if (!mod) {
const generate = GENERATORS[toolId];
if (!generate) {
return { success: false, configPath: "", error: `Unknown tool: ${toolId}` };
}
const content = await mod.generate(options);
const content = await generate(options);
const configPath = TOOL_CONFIG_PATHS[toolId] || "";
return { success: true, configPath, content };
} catch (err) {

View File

@@ -2,10 +2,28 @@
import React from "react";
import { act } from "react";
import { createRoot } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const cleanupCallbacks: Array<() => void> = [];
function createTestStorage(): Storage {
const entries = new Map<string, string>();
return {
get length() {
return entries.size;
},
clear: () => entries.clear(),
getItem: (key) => entries.get(key) ?? null,
key: (index) => Array.from(entries.keys())[index] ?? null,
removeItem: (key) => {
entries.delete(key);
},
setItem: (key, value) => {
entries.set(key, value);
},
};
}
function makeContainer(): HTMLElement {
const container = document.createElement("div");
document.body.appendChild(container);
@@ -20,6 +38,7 @@ describe("AutoRoutingBanner", () => {
(
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
).IS_REACT_ACT_ENVIRONMENT = true;
vi.stubGlobal("localStorage", createTestStorage());
localStorage.clear();
});
@@ -29,6 +48,7 @@ describe("AutoRoutingBanner", () => {
}
document.body.innerHTML = "";
localStorage.clear();
vi.unstubAllGlobals();
});
it("renders banner on first mount", async () => {

View File

@@ -100,7 +100,7 @@ describe("Protocol clients E2E", () => {
async () => {
const transport = new StdioClientTransport({
command: process.execPath,
args: ["--import", "tsx/esm", "open-sse/mcp-server/server.ts"],
args: ["--import", "tsx", "open-sse/mcp-server/server.ts"],
env: {
...process.env,
OMNIROUTE_BASE_URL: BASE_URL,

View File

@@ -305,13 +305,14 @@ test.describe("Resilience Plan Alignment", () => {
await mockResilienceSettings(page);
await gotoDashboardRoute(page, "/dashboard/settings?tab=resilience");
const resiliencePanel = page.getByRole("tabpanel", { name: "Resilience" });
await expect(
page.getByRole("heading", { name: "Connection Cooldown", exact: true })
resiliencePanel.getByRole("heading", { name: "Connection Cooldown", exact: true })
).toBeVisible({ timeout: 15000 });
await expect(page.getByText("Base cooldown", { exact: true }).first()).toBeVisible();
await expect(page.getByText("Use upstream retry hints", { exact: true }).first()).toBeVisible();
await expect(page.getByText("Max backoff steps", { exact: true }).first()).toBeVisible();
await expect(page.getByText(/Rate-limit fallback/i)).toHaveCount(0);
await expect(resiliencePanel.getByText(/Cooldown base\s*60000ms/)).toBeVisible();
await expect(resiliencePanel.getByText(/Use upstream retry hints\s*No/)).toBeVisible();
await expect(resiliencePanel.getByText(/Max backoff steps\s*8/)).toBeVisible();
await expect(resiliencePanel.getByText(/Rate-limit fallback/i)).toHaveCount(0);
});
test("health page renders provider breaker runtime state for multiple providers", async ({

View File

@@ -13,7 +13,7 @@
*
* To run:
* CURSOR_E2E_TOKEN=$(cat ~/.cursor/access-token) \
* node --import tsx/esm --test tests/integration/cursor-e2e.test.ts
* node --import tsx --test tests/integration/cursor-e2e.test.ts
*
* Capturing wire fixtures (separate workflow):
* CURSOR_TOKEN=... node scripts/ad-hoc/cursor-tap.cjs single-turn-chat "say PING"

View File

@@ -4,7 +4,7 @@
* Tests bulk data operations against acceptable time thresholds.
* Thresholds are 2x the expected target to account for slow CI machines.
*
* Run: node --import tsx/esm --test tests/integration/performance-regression.test.ts
* Run: node --import tsx --test tests/integration/performance-regression.test.ts
*/
import { describe, it, before, after } from "node:test";

View File

@@ -4,6 +4,7 @@ import assert from "node:assert/strict";
import { createChatPipelineHarness } from "../integration/_chatPipelineHarness.ts";
process.env.STREAM_IDLE_TIMEOUT_MS = "50";
process.env.STREAM_READINESS_TIMEOUT_MS = "50";
const harness = await createChatPipelineHarness("chat-cooldown-aware-retry");
const auth = await import("../../src/sse/services/auth.ts");
@@ -241,9 +242,7 @@ test("handleChat returns model_cooldown when every credential for the requested
assert.ok(Number(response.headers.get("Retry-After")) >= 1);
});
test("handleChat returns stream readiness timeout without entering cooldown-aware retry or account lockout", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout"] });
try {
test("handleChat returns stream readiness timeout without entering cooldown-aware retry or account lockout", async () => {
const connection = await seedConnection("openai", {
apiKey: "sk-openai-stream-readiness-timeout",
});
@@ -258,7 +257,7 @@ test("handleChat returns stream readiness timeout without entering cooldown-awar
return buildZombieSseResponse();
};
const responsePromise = handleChat(
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
@@ -267,13 +266,6 @@ test("handleChat returns stream readiness timeout without entering cooldown-awar
},
})
);
// Give the async pipeline a chance to settle and start the fetch
await new Promise((resolve) => process.nextTick(resolve));
// Fast-forward past the default 30s stream readiness timeout
t.mock.timers.tick(30500);
const response = await responsePromise;
const body = (await response.json()) as any;
assert.equal(response.status, 504);
@@ -285,9 +277,6 @@ test("handleChat returns stream readiness timeout without entering cooldown-awar
assert.ok(refreshedConnection.rateLimitedUntil == null);
assert.ok(refreshedConnection.errorCode == null);
assert.equal(refreshedConnection.backoffLevel, 0);
} finally {
t.mock.timers.reset();
}
});
test("handleChat aborts the pending cooldown wait when the client disconnects", async () => {

View File

@@ -140,13 +140,16 @@ test("Command Code executor posts wrapped body and required headers to alpha/gen
});
test("Command Code raw NDJSON stream becomes OpenAI chat SSE chunks", async () => {
globalThis.fetch = async () =>
commandCodeStream([
const calls: any[] = [];
globalThis.fetch = async (url, init = {}) => {
calls.push({ url: String(url), init, body: JSON.parse(String(init.body)) });
return commandCodeStream([
{ type: "text-delta", text: "Hello" },
{ type: "reasoning-delta", text: "thinking" },
{ type: "tool-call", toolCallId: "call_1", toolName: "search", input: { q: "docs" } },
{ type: "finish", finishReason: "tool-calls" },
]);
};
const { response } = await getExecutor("command-code").execute({
model: "gpt-5.4",
@@ -155,6 +158,7 @@ test("Command Code raw NDJSON stream becomes OpenAI chat SSE chunks", async () =
body: { messages: [{ role: "user", content: "Hi" }] },
});
assert.equal(calls[0].body.params.stream, true);
assert.equal(response.headers.get("Content-Type"), "text/event-stream; charset=utf-8");
const sse = await response.text();
assert.match(sse, /data: \[DONE\]/);

View File

@@ -85,6 +85,9 @@ test("machineId: falls back to Linux machine-id files before hostname", async ()
fs.existsSync = () => false;
fs.readFileSync = (filePath, encoding) => {
if (filePath !== "/etc/machine-id") {
return originalReadFileSync(filePath, encoding);
}
assert.equal(filePath, "/etc/machine-id");
assert.equal(encoding, "utf8");
return "LINUX-MACHINE-ID\n";

View File

@@ -2,10 +2,28 @@
import React from "react";
import { act } from "react";
import { createRoot } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const cleanupCallbacks: Array<() => void> = [];
function createTestStorage(): Storage {
const entries = new Map<string, string>();
return {
get length() {
return entries.size;
},
clear: () => entries.clear(),
getItem: (key) => entries.get(key) ?? null,
key: (index) => Array.from(entries.keys())[index] ?? null,
removeItem: (key) => {
entries.delete(key);
},
setItem: (key, value) => {
entries.set(key, value);
},
};
}
function makeContainer(): HTMLElement {
const container = document.createElement("div");
document.body.appendChild(container);
@@ -20,6 +38,7 @@ describe("AutoRoutingBanner", () => {
(
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
).IS_REACT_ACT_ENVIRONMENT = true;
vi.stubGlobal("localStorage", createTestStorage());
localStorage.clear();
});
@@ -29,6 +48,7 @@ describe("AutoRoutingBanner", () => {
}
document.body.innerHTML = "";
localStorage.clear();
vi.unstubAllGlobals();
});
it("renders banner on first mount", async () => {

View File

@@ -10,6 +10,23 @@ function decodeChunk(value) {
return typeof value === "string" ? value : new TextDecoder().decode(value);
}
async function readWithTimeout(reader, timeoutMs = 250) {
let timeout;
try {
return await Promise.race([
reader.read(),
new Promise((_, reject) => {
timeout = setTimeout(
() => reject(new Error("Timed out waiting for SSE heartbeat")),
timeoutMs
);
}),
]);
} finally {
clearTimeout(timeout);
}
}
test("integration: anthropic-ping heartbeat reaches downstream and does NOT trigger stream.ts strip", async () => {
// Build a fake upstream that emits one chunk then idles indefinitely
let cancelled = false;
@@ -39,7 +56,7 @@ test("integration: anthropic-ping heartbeat reaches downstream and does NOT trig
const startedAt = Date.now();
let sawPing = false;
while (Date.now() - startedAt < 200) {
const { value, done } = await reader.read();
const { value, done } = await readWithTimeout(reader);
if (done) break;
const chunk = decodeChunk(value);
if (/^event: ping\b/m.test(chunk)) {
@@ -83,7 +100,7 @@ test("integration: openai-chunk heartbeat is valid JSON parseable by SDKs", asyn
const startedAt = Date.now();
let sawValidChunk = false;
while (Date.now() - startedAt < 200) {
const { value, done } = await reader.read();
const { value, done } = await readWithTimeout(reader);
if (done) break;
const chunk = decodeChunk(value);
if (chunk.startsWith("data: ") && chunk.includes("omniroute-keepalive")) {
@@ -118,7 +135,7 @@ test("integration: shapeForClientFormat + createSseHeartbeatTransform pipeline (
const reader = upstream.pipeThrough(transform).getReader();
await reader.read(); // first real
const { value } = await reader.read();
const { value } = await readWithTimeout(reader);
assert.match(decodeChunk(value), /^event: ping\ndata: \{\}\n\n$/);
await reader.cancel();
});