Reviewed and approved via consolidated analysis. Turkish locale (31st language) follows existing i18n patterns perfectly. Registered in config.ts, generate-multilang.mjs, and full tr.json translation file.
- Use globalThis singleton guards for DB connection, HealthCheck timers, console interceptor, and graceful shutdown to survive Webpack HMR re-evaluation (fixes 485+ leaked DB connections per session)
- Split instrumentation.ts into instrumentation-node.ts with computed import path to prevent Turbopack Edge bundler from tracing Node.js modules (eliminates 10+ spurious warnings per hot compile)
- Parallelize startup imports in instrumentation-node.ts (3 batch Promise.all instead of 9 serial awaits)
- Add OMNIROUTE_USE_TURBOPACK=1 env switch in run-next.mjs (default behavior unchanged)
- Replace node:crypto with crypto in proxies.ts and errorResponse.ts to fix UnhandledSchemeError
- Add unlinkFileWithRetry with EBUSY/EPERM retry for Windows file handle timing in backup restore
- Fix pre-restore backup to await completion before closing DB
- Fix bootstrap-env, domain-persistence, and fixes-p1 test stability on Windows
Made-with: Cursor
- #462: Mark gemini-cli provider as deprecated in providers.ts
Add deprecated, deprecationReason, hasFree, freeNote, authHint, apiHint
to Zod provider schema
- #471: Add VM_DEPLOYMENT_GUIDE.md to DOC_SOURCE_FILES in generate-multilang.mjs
Delete 29 stale PT-language copies and regenerate from EN source
for all 30 locales (29 auto-translated + 1 Czech from PR #482)
npm version patch run BEFORE staging files — this is an ATOMIC commit.
Adds Strategy 1.5 to scripts/postinstall.mjs:
- Uses @mapbox/node-pre-gyp install --fallback-to-build=false
(bundled within better-sqlite3) to download the correct prebuilt
binary for the current OS/arch (win32-x64/arm64, darwin-x64/arm64)
WITHOUT requiring node-gyp, Python, or MSVC build tools.
- Tries node-pre-gyp.cmd (Windows) or node-pre-gyp (Unix) from .bin/
with fallback to direct path in @mapbox/node-pre-gyp/bin/
- Falls back to npm rebuild only if prebuilt download fails.
- Windows-specific error: shows Option A (npx node-pre-gyp) and
Option B (rebuild) with Visual Studio Build Tools links.
Fixes: #426 (better_sqlite3.node is not a valid Win32 application)
Even with EXPERIMENTAL_TURBOPACK=0 and NEXT_PRIVATE_BUILD_WORKER=0, Next.js 16
instrumentation chunks still emit require('better-sqlite3-<16hexchars>') and
require('zod-<16hexchars>') into the compiled .js files inside .next/server/.
The webpack externals function in next.config.mjs patches the runtime bundler
but does NOT rewrite already-compiled chunks. Added step 5.6 to prepublish.mjs:
walks all .js files in app/.next/server/ and strips the 16-char hex suffix from
any require() string that matches the Turbopack hash pattern.
Also updated deploy-vps workflow: npm registry rejects 299MB packages, so
deployment now uses npm pack + scp + npm install -g /tmp/omniroute-*.tgz.
PM2 entry point is app/server.js inside the npm global package.
Turbopack in Next.js 16 hashes ALL serverExternalPackages (not just better-sqlite3),
emitting require() calls like 'zod-dcb22c6336e0bc69', 'pino-28069d5257187539' etc.
that don't exist in node_modules.
Changes:
- next.config.mjs: Replace single-package check with a HASH_PATTERN regex
that strips '<name>-<16hexchars>' suffix for any externalized package.
Also adds KNOWN_EXTERNALS set for exact-name matching.
- scripts/prepublish.mjs: Add NEXT_PRIVATE_BUILD_WORKER=0 env to reinforce
webpack mode. Add post-build scan that reports hashed refs so CI is visible.
Closes#396, addresses #398
Match both slash styles when removing build-machine paths from the
staged standalone bundle so the sanitization step works on Windows
and POSIX builds.
While touching the helper, replace the custom basename logic with
Node's built-in `path.basename` for clarity.
Prepare a dedicated `.next/electron-standalone` bundle before
running electron-builder so desktop packaging operates on a stable,
Electron-specific server payload.
This also adds a preflight that rejects standalone bundles whose
top-level `node_modules` is a symlink, because electron-builder
preserves `extraResources` symlinks and would otherwise ship an app
that depends on the build machine at runtime.
Keep getPreferredEnvFilePath consistent with its env parameter by
passing that env through resolveDataDir in both bootstrap and Electron.
This avoids silently falling back to process.env when a custom env map
is supplied.
Treat empty or whitespace-only dataDirOverride values as unset so
bootstrapEnv keeps using the normal DATA_DIR and .env lookup path.
Adds a focused regression test for the whitespace override case.
Propagate database inspection failures instead of treating them as
missing encrypted credentials.
This keeps startup from generating a fresh encryption key when an
existing database cannot be inspected and adds a regression test for
that path.
Align the app bootstrap paths with the documented CLI env lookup.
The CLI wrapper already loads DATA_DIR/.env, ~/.omniroute/.env, or ./.env,
but run-next, run-standalone, and Electron were bypassing that behavior.
On machines with encrypted credentials, that could generate a fresh
STORAGE_ENCRYPTION_KEY in server.env and make existing tokens unreadable.
This change:
- uses the same preferred .env lookup in bootstrapEnv and Electron
- keeps Electron secrets rooted in DATA_DIR and passes DATA_DIR to the child
- refuses to mint a new encryption key over an existing encrypted database
- adds a focused regression test for env precedence and key safety
- docs/openapi.yaml: update info.version from 2.3.6 to 2.4.1 (fixes CI check)
- CHANGELOG.md: add '## [Unreleased]' section as first heading (required by check-docs-sync)
- scripts/check-docs-sync.mjs: fix regex to accept both hyphen (-) and em-dash (—)
as date separators in changelog headings (standard Keep a Changelog format)
- .husky/pre-commit: add 'node scripts/check-docs-sync.mjs' to catch version
mismatches locally before push
- fix(oauth): restore iFlow clientSecret default — was empty string, now uses the valid public key (#339)
- fix(mitm): compile src/mitm/*.ts to JS during prepublish so server.js exists in npm bundle (#335)
- fix(gemini-cli): graceful projectId fallback — warn + empty string instead of hard 500 error (#338)
- feat(models): add gpt5.4 to Codex; add claude-sonnet-4, claude-opus-4.6, deepseek-v3.2, minimax-m2.1, qwen3-coder-next, auto to Kiro (#334)
- fix(electron): sync electron/package.json version to 2.3.13 (#323)
- feat(scoring): add tierPriority (0.05) to ScoringWeights Zod schema and combos/auto API route
prepublish.mjs: explicitly copy @swc/helpers into standalone app/node_modules
before packaging. npm tarball will always include it.
postinstall.mjs: fallback copy of @swc/helpers from root node_modules into
app/node_modules/@swc/ when missing after npm install -g.
Fixes server crash after npm install -g omniroute.
- Read only first 4096 bytes of binary header instead of entire file
- Add error logging to all catch blocks with specific failure messages
- Separate copy vs dlopen catch blocks in postinstall Strategy 1
- Add archCount sanity cap (max 30) for fat Mach-O parsing
- Distinguish timeout vs rebuild failure in Strategy 2
Add native-binary-compat module that reads ELF/Mach-O/PE headers to
determine the actual target platform/arch of the .node binary. This
eliminates the macOS false-positive where dlopen loads a linux-x64
binary without throwing.
- Parse ELF (linux), Mach-O (darwin), and PE (win32) binary formats
- Use header-based check as primary signal, dlopen as secondary
- Update pre-flight check in CLI to use the new module
- Add unit tests for all binary formats and cross-platform scenarios
The standalone app/ directory created by Next.js only contains runtime
files for better-sqlite3 (no binding.gyp, no source, no prebuild-install),
so `npm rebuild` inside app/ is a no-op. The previous fix (#312) added
exit(1) on rebuild failure, which caused npm to rollback the entire
package installation — leaving users with nothing to fix manually.
New approach:
1. Check if existing binary is already compatible (dlopen)
2. Copy the correctly-built binary from root node_modules/ (npm already
compiles it for the correct platform during install)
3. Fall back to npm rebuild if root binary is unavailable
4. Warn but don't fail the install if nothing works — the package stays
installed and the CLI pre-flight check gives a clear error at startup
Replace unreliable process.dlopen() platform detection with explicit
platform/arch comparison against the build target (linux-x64). On macOS,
dlopen can load an incompatible binary without throwing, causing the
postinstall script to skip the rebuild entirely.
- Detect platform mismatch via process.platform/arch instead of dlopen
- Fail the install (exit 1) if rebuild fails, instead of warning silently
- Verify rebuilt binary loads correctly after rebuild
- Add pre-flight binary check in CLI entry point as a safety net
The healthcheck script was querying /api/settings which returns config
data rather than system health. Updated to /api/monitoring/health which
is the canonical health endpoint used across tests, SystemMonitor.tsx,
MaintenanceBanner.tsx, playwright config, and MCP tools.
Resolves root cause of #252 (Electron black screen) and #249 (OAuth fail)
for users running with zero configuration (no .env needed).
New: scripts/bootstrap-env.mjs
- Auto-generates JWT_SECRET (64 bytes), STORAGE_ENCRYPTION_KEY (32 bytes),
API_KEY_SECRET (32 bytes) if missing or empty
- Persists to {DATA_DIR}/server.env — survives restarts, Docker volume
remounts, and upgrades without changing secrets
- Reads .env from CWD (user overrides), then merges process.env (highest prio)
- Logs friendly warnings for missing optional OAuth secrets
Updated: run-standalone.mjs + run-next.mjs
- Call bootstrapEnv() before spawning server — covers npm + Docker paths
Updated: electron/main.js (synchronous inline — CJS cannot await import ESM)
- Reads userData/server.env, generates missing secrets with crypto.randomBytes()
- Persists back to server.env, sets OMNIROUTE_BOOTSTRAPPED=true
New: BootstrapBanner.tsx + page.tsx update
- Dismissable amber banner on dashboard home when running in zero-config mode
- Shows where server.env is located and how to customize secrets
Introduce full AI orchestration ecosystem:
- MCP Server with 16 tools, scoped auth, and audit logging
- A2A v0.3 server with JSON-RPC 2.0, SSE streaming, and task manager
- Auto-Combo engine with 6-factor scoring and self-healing
- VS Code extension with smart dispatch and budget tracking
- Harden CI pipeline: add static checks, remove continue-on-error
- Add translator schema validation tests
- Update .gitignore and CHANGELOG for release checklist
- Add unit tests for 8 MCP advanced tool handlers (Phase 3)
- Migrate test files from JavaScript to TypeScript (.ts/.tsx)
- Restructure file paths from app/ to src/app/ across all tests
- Refactor route assertions into reusable assertRouteMethods helper
- Add tests for new API routes (compliance, audit-log, evals/[suiteId])
- Update barrel export tests to use consolidated assertion pattern
Next.js standalone bakes absolute build-time paths (outputFileTracingRoot,
appDir, turbopack root) into server.js and required-server-files.json.
When installed via npm on a different machine, these paths don't exist,
causing ENOENT errors. The prepublish script now replaces build-machine
absolute paths with '.' (relative) so they resolve correctly wherever
the package is installed.
The npm package ships with better-sqlite3 compiled for Linux x64.
On Windows and macOS, the binary is incompatible and fails to load.
Added postinstall script that:
- Detects if the bundled native module is incompatible
- Automatically runs 'npm rebuild better-sqlite3' to compile for the target platform
- Provides manual fallback instructions if rebuild fails