From f3b944a55a67f5225d343ba7f26d49fad52d0e09 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Wed, 13 May 2026 10:14:25 -0300 Subject: [PATCH] refactor(scripts): organize into build/dev/check/docs/i18n/ad-hoc subfolders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganizes the 29 active scripts under scripts/ into purpose-driven subfolders: - scripts/build/ (11) — Build, install, publish, runtime env - scripts/dev/ (13) — Dev servers, test runners, healthchecks - scripts/check/ (10) — Lint/validation/coverage checks - scripts/docs/ (2) — Docs index and provider reference generation - scripts/i18n/ (+3) — Adds Python translation utilities (check/validate/autotranslate) - scripts/ad-hoc/ (4) — One-shot maintenance utilities Updates all references in package.json, electron/package.json, .husky/pre-commit, .github/workflows/ci.yml, Dockerfile, src/, tests/, scripts/ internal cross-imports, playwright.config.ts, and English docs (CODEBASE_DOCUMENTATION, ENVIRONMENT, FEATURES, RELEASE_CHECKLIST, COVERAGE_PLAN, ELECTRON_GUIDE, I18N, GEMINI). Also patches scripts/build/pack-artifact-policy.ts so the npm pack allowlist mirrors the new layout. Validates with: - npm run lint (exit 0 — pre-existing minified-bundle errors only) - npm run typecheck:core (exit 0) - npm run check:docs-all (exit 0) - unit tests for moved scripts (57 tests pass) Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 6 +- .husky/pre-commit | 2 +- Dockerfile | 16 ++--- GEMINI.md | 4 +- docs/CODEBASE_DOCUMENTATION.md | 43 ++++++------ docs/COVERAGE_PLAN.md | 2 +- docs/ELECTRON_GUIDE.md | 12 ++-- docs/ENVIRONMENT.md | 26 +++---- docs/FEATURES.md | 2 +- docs/I18N.md | 46 ++++++------- docs/RELEASE_CHECKLIST.md | 2 +- electron/package.json | 4 +- package.json | 68 +++++++++---------- playwright.config.ts | 2 +- scripts/{ => ad-hoc}/cursor-tap.cjs | 4 +- scripts/{ => ad-hoc}/dbsetup.js | 0 scripts/{ => ad-hoc}/migrate-env.mjs | 0 scripts/{ => ad-hoc}/sync-cursor-models.mjs | 6 +- scripts/{ => build}/bootstrap-env.mjs | 2 +- scripts/{ => build}/build-next-isolated.mjs | 2 +- scripts/{ => build}/native-binary-compat.mjs | 0 scripts/{ => build}/pack-artifact-policy.ts | 22 +++--- scripts/{ => build}/postinstall.mjs | 2 +- scripts/{ => build}/postinstallSupport.mjs | 0 .../prepare-electron-standalone.mjs | 2 +- scripts/{ => build}/prepublish.ts | 10 +-- scripts/{ => build}/runtime-env.mjs | 0 scripts/{ => build}/uninstall.mjs | 0 scripts/{ => build}/validate-pack-artifact.ts | 2 +- scripts/{ => check}/check-cycles.mjs | 0 .../{ => check}/check-deprecated-versions.mjs | 6 +- .../{ => check}/check-docs-counts-sync.mjs | 4 +- scripts/{ => check}/check-docs-sync.mjs | 0 scripts/{ => check}/check-env-doc-sync.mjs | 6 +- scripts/{ => check}/check-pr-test-policy.mjs | 15 ++-- .../{ => check}/check-route-validation.mjs | 0 .../check-supported-node-runtime.ts | 2 +- scripts/{ => check}/check-t11-any-budget.mjs | 0 scripts/{ => check}/test-report-summary.mjs | 0 scripts/{ => dev}/healthcheck.mjs | 0 scripts/{ => dev}/responses-ws-proxy.mjs | 0 scripts/{ => dev}/run-ecosystem-tests.mjs | 2 +- scripts/{ => dev}/run-next-playwright.mjs | 4 +- scripts/{ => dev}/run-next.mjs | 4 +- scripts/{ => dev}/run-playwright-tests.mjs | 2 +- .../{ => dev}/run-protocol-clients-tests.mjs | 2 +- scripts/{ => dev}/run-standalone.mjs | 4 +- scripts/{ => dev}/smoke-electron-packaged.mjs | 2 +- scripts/{ => dev}/standalone-server-ws.mjs | 0 scripts/{ => dev}/sync-env.mjs | 0 scripts/{ => dev}/system-info.mjs | 4 +- scripts/{ => dev}/v1-ws-bridge.mjs | 0 scripts/{ => docs}/gen-provider-reference.ts | 6 +- scripts/{ => docs}/generate-docs-index.mjs | 12 ++-- scripts/{ => i18n}/check_translations.py | 6 +- scripts/{ => i18n}/i18n_autotranslate.py | 2 +- scripts/{ => i18n}/validate_translation.py | 6 +- src/app/api/system/env/repair/route.ts | 2 +- src/app/api/system/version/route.ts | 2 +- src/app/docs/lib/docs-auto-generated.ts | 4 +- src/lib/oauth/constants/oauth.ts | 2 +- src/lib/system/autoUpdate.ts | 2 +- tests/fixtures/cursor/.gitignore | 2 +- .../integration/batch-e2e-rate-limit.test.ts | 2 +- tests/integration/cursor-e2e.test.ts | 2 +- tests/integration/resilience-http-e2e.test.ts | 2 +- tests/unit/bootstrap-env.test.ts | 2 +- tests/unit/build-next-isolated.test.ts | 2 +- tests/unit/electron-smoke-script.test.ts | 2 +- tests/unit/native-binary-compat.test.ts | 2 +- tests/unit/pack-artifact-policy.test.ts | 20 +++--- tests/unit/postinstall-support.test.ts | 2 +- tests/unit/responses-ws-proxy.test.mjs | 2 +- tests/unit/run-next-playwright.test.ts | 2 +- tests/unit/runtime-env.test.ts | 2 +- tests/unit/runtime-ports.test.ts | 2 +- tests/unit/sync-env.test.ts | 2 +- tests/unit/v1-ws-bridge.test.ts | 2 +- 78 files changed, 225 insertions(+), 213 deletions(-) rename scripts/{ => ad-hoc}/cursor-tap.cjs (97%) rename scripts/{ => ad-hoc}/dbsetup.js (100%) rename scripts/{ => ad-hoc}/migrate-env.mjs (100%) rename scripts/{ => ad-hoc}/sync-cursor-models.mjs (93%) rename scripts/{ => build}/bootstrap-env.mjs (99%) rename scripts/{ => build}/build-next-isolated.mjs (98%) rename scripts/{ => build}/native-binary-compat.mjs (100%) rename scripts/{ => build}/pack-artifact-policy.ts (90%) rename scripts/{ => build}/postinstall.mjs (99%) rename scripts/{ => build}/postinstallSupport.mjs (100%) rename scripts/{ => build}/prepare-electron-standalone.mjs (99%) rename scripts/{ => build}/prepublish.ts (98%) rename scripts/{ => build}/runtime-env.mjs (100%) rename scripts/{ => build}/uninstall.mjs (100%) rename scripts/{ => build}/validate-pack-artifact.ts (98%) rename scripts/{ => check}/check-cycles.mjs (100%) rename scripts/{ => check}/check-deprecated-versions.mjs (95%) rename scripts/{ => check}/check-docs-counts-sync.mjs (96%) rename scripts/{ => check}/check-docs-sync.mjs (100%) rename scripts/{ => check}/check-env-doc-sync.mjs (96%) rename scripts/{ => check}/check-pr-test-policy.mjs (90%) rename scripts/{ => check}/check-route-validation.mjs (100%) rename scripts/{ => check}/check-supported-node-runtime.ts (91%) rename scripts/{ => check}/check-t11-any-budget.mjs (100%) rename scripts/{ => check}/test-report-summary.mjs (100%) rename scripts/{ => dev}/healthcheck.mjs (100%) rename scripts/{ => dev}/responses-ws-proxy.mjs (100%) rename scripts/{ => dev}/run-ecosystem-tests.mjs (97%) rename scripts/{ => dev}/run-next-playwright.mjs (98%) rename scripts/{ => dev}/run-next.mjs (96%) rename scripts/{ => dev}/run-playwright-tests.mjs (91%) rename scripts/{ => dev}/run-protocol-clients-tests.mjs (97%) rename scripts/{ => dev}/run-standalone.mjs (76%) rename scripts/{ => dev}/smoke-electron-packaged.mjs (99%) rename scripts/{ => dev}/standalone-server-ws.mjs (100%) rename scripts/{ => dev}/sync-env.mjs (100%) rename scripts/{ => dev}/system-info.mjs (98%) rename scripts/{ => dev}/v1-ws-bridge.mjs (100%) rename scripts/{ => docs}/gen-provider-reference.ts (97%) rename scripts/{ => docs}/generate-docs-index.mjs (94%) rename scripts/{ => i18n}/check_translations.py (97%) rename scripts/{ => i18n}/i18n_autotranslate.py (97%) rename scripts/{ => i18n}/validate_translation.py (99%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96036f2971..d8a8b13a79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: - name: Validate ${{ matrix.lang }} run: | - python3 scripts/validate_translation.py quick -l '${{ matrix.lang }}' > result.txt + python3 scripts/i18n/validate_translation.py quick -l '${{ matrix.lang }}' > result.txt - name: Upload result if: always() @@ -94,7 +94,7 @@ jobs: - name: Fetch base branch run: git fetch --no-tags origin "${GITHUB_BASE_REF}" --depth=1 - name: Validate source changes include tests - run: node scripts/check-pr-test-policy.mjs --summary-file .artifacts/pr-test-policy.md + run: node scripts/check/check-pr-test-policy.mjs --summary-file .artifacts/pr-test-policy.md - name: Publish PR test policy summary if: always() run: | @@ -255,7 +255,7 @@ jobs: run: | mkdir -p coverage if [ -f coverage/coverage-summary.json ]; then - node scripts/test-report-summary.mjs \ + node scripts/check/test-report-summary.mjs \ --input coverage/coverage-summary.json \ --output coverage/coverage-report.md \ --threshold 60 diff --git a/.husky/pre-commit b/.husky/pre-commit index 7fad3fc22f..5b6946b171 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -6,5 +6,5 @@ if ! command -v npx >/dev/null 2>&1; then fi npx lint-staged -node scripts/check-docs-sync.mjs +node scripts/check/check-docs-sync.mjs npm run check:any-budget:t11 diff --git a/Dockerfile b/Dockerfile index c642feb630..bf41ee8585 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,9 +6,9 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* COPY package*.json ./ -COPY scripts/postinstall.mjs ./scripts/postinstall.mjs -COPY scripts/postinstallSupport.mjs ./scripts/postinstallSupport.mjs -COPY scripts/native-binary-compat.mjs ./scripts/native-binary-compat.mjs +COPY scripts/build/postinstall.mjs ./scripts/build/postinstall.mjs +COPY scripts/build/postinstallSupport.mjs ./scripts/build/postinstallSupport.mjs +COPY scripts/build/native-binary-compat.mjs ./scripts/build/native-binary-compat.mjs ENV NPM_CONFIG_LEGACY_PEER_DEPS=true RUN if [ -f package-lock.json ]; then \ npm ci --no-audit --no-fund --legacy-peer-deps; \ @@ -60,17 +60,17 @@ COPY --from=builder /app/src/mitm/server.cjs ./src/mitm/server.cjs # Next.js standalone tracing does not include them. COPY --from=builder /app/docs ./docs -COPY --from=builder /app/scripts/run-standalone.mjs ./run-standalone.mjs -COPY --from=builder /app/scripts/runtime-env.mjs ./runtime-env.mjs -COPY --from=builder /app/scripts/bootstrap-env.mjs ./bootstrap-env.mjs -COPY --from=builder /app/scripts/healthcheck.mjs ./healthcheck.mjs +COPY --from=builder /app/scripts/dev/run-standalone.mjs ./dev/run-standalone.mjs +COPY --from=builder /app/scripts/build/runtime-env.mjs ./build/runtime-env.mjs +COPY --from=builder /app/scripts/build/bootstrap-env.mjs ./build/bootstrap-env.mjs +COPY --from=builder /app/scripts/dev/healthcheck.mjs ./healthcheck.mjs EXPOSE 20128 HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ CMD ["node", "healthcheck.mjs"] -CMD ["node", "run-standalone.mjs"] +CMD ["node", "dev/run-standalone.mjs"] FROM runner-base AS runner-cli diff --git a/GEMINI.md b/GEMINI.md index c927102d37..24f3401c4d 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -5,7 +5,7 @@ ## 1. File Placement & Organization - **Test Files**: ALL unit tests, integration tests, ecosystem tests, or Vitest files MUST strictly be placed within the `tests/` directory (e.g., `tests/unit/`, `tests/integration/`). NEVER create test files in the project root (`/`). -- **Scripts and Utilities**: ALL maintenance, debugging, generation, or experimental scripts (`.cjs`, `.mjs`, `.js`, `.ts`) MUST be placed strictly inside the `scripts/` directory or `scripts/scratch/` for temporary one-offs. NEVER dump loose scripts in the project root (`/`). +- **Scripts and Utilities**: ALL maintenance, debugging, generation, or experimental scripts (`.cjs`, `.mjs`, `.js`, `.ts`) MUST be placed strictly inside one of the `scripts/` subfolders (`build/`, `dev/`, `check/`, `docs/`, `i18n/`, `ad-hoc/`). One-shot or experimental code goes under `scripts/ad-hoc/`. NEVER dump loose scripts in the project root (`/`) or the top-level `scripts/` folder. **The Project Root MUST ONLY CONTAIN:** @@ -14,7 +14,7 @@ - Documentation files (`README.md`, `CHANGELOG.md`, `LICENSE`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `llm.txt`, `Tuto_Qdrant.md`) - CI/CD files and ignore definitions (`.gitignore`, `.dockerignore`, `.npmignore`, `.npmrc`, `.node-version`, `.nvmrc`, `.env.example`) -When creating _any_ validation tests or one-off logic scripts, default to using `scripts/scratch/` or the `tests/unit/` directories according to your goals. Do not pollute the `/` root context. +When creating _any_ validation tests or one-off logic scripts, default to using `scripts/ad-hoc/` or the `tests/unit/` directories according to your goals. Do not pollute the `/` root context. ## 2. Hard Rules (mirror of `CLAUDE.md`) diff --git a/docs/CODEBASE_DOCUMENTATION.md b/docs/CODEBASE_DOCUMENTATION.md index bf8bdf5d31..305c769176 100644 --- a/docs/CODEBASE_DOCUMENTATION.md +++ b/docs/CODEBASE_DOCUMENTATION.md @@ -25,7 +25,7 @@ without inventing new modules. | Database | **SQLite** via `better-sqlite3` (singleton, WAL journaling) | | Desktop | **Electron 41** + `electron-builder` 26.10 (separate workspace at `electron/`) | | Tests | **Node native test runner** (unit/integration), **Vitest** (MCP, autoCombo, cache), **Playwright** (e2e + protocols-e2e) | -| Build | Next.js standalone via `scripts/build-next-isolated.mjs` | +| Build | Next.js standalone via `scripts/build/build-next-isolated.mjs` | | Lint/format | ESLint flat config + Prettier (`lint-staged` via Husky pre-commit) | | Module system | ESM everywhere (`"type": "module"`) | | Workspaces | npm workspace — `open-sse` is the only sub-workspace | @@ -613,26 +613,31 @@ Common commands: ## 8. `scripts/` -42 scripts. Highlights: +Organized into 6 subfolders by purpose. -- **Build / runtime**: `build-next-isolated.mjs`, `prepare-electron-standalone.mjs`, - `run-next.mjs`, `run-next-playwright.mjs`, `run-standalone.mjs`, - `standalone-server-ws.mjs`, `responses-ws-proxy.mjs`, `v1-ws-bridge.mjs`, - `runtime-env.mjs`, `bootstrap-env.mjs`, `smoke-electron-packaged.mjs`. -- **Checks**: `check-cycles.mjs`, `check-docs-sync.mjs`, - `check-route-validation.mjs`, `check-t11-any-budget.mjs`, - `check-pr-test-policy.mjs`, `check-supported-node-runtime.ts`, +- **`scripts/build/`** — `build-next-isolated.mjs`, `prepublish.ts`, + `prepare-electron-standalone.mjs`, `pack-artifact-policy.ts`, + `validate-pack-artifact.ts`, `postinstall.mjs`, `postinstallSupport.mjs`, + `uninstall.mjs`, `bootstrap-env.mjs`, `runtime-env.mjs`, `native-binary-compat.mjs`. -- **Generators / sync**: `generate-docs-index.mjs`, `sync-env.mjs`, - `sync-cursor-models.mjs`, `migrate-env.mjs`. -- **Install / publish**: `postinstall.mjs`, `postinstallSupport.mjs`, - `prepublish.ts`, `pack-artifact-policy.ts`, `validate-pack-artifact.ts`, - `uninstall.mjs`. -- **Test runners**: `run-playwright-tests.mjs`, `run-ecosystem-tests.mjs`, - `run-protocol-clients-tests.mjs`, `test-report-summary.mjs`. -- **Misc**: `healthcheck.mjs`, `dbsetup.js`, `system-info.mjs`, - `cursor-tap.cjs`, `scratch.mjs`, `i18n_autotranslate.py`, - `check_translations.py`, `validate_translation.py`. +- **`scripts/dev/`** — `run-next.mjs`, `run-next-playwright.mjs`, + `run-standalone.mjs`, `standalone-server-ws.mjs`, `responses-ws-proxy.mjs`, + `v1-ws-bridge.mjs`, `smoke-electron-packaged.mjs`, + `run-playwright-tests.mjs`, `run-ecosystem-tests.mjs`, + `run-protocol-clients-tests.mjs`, `sync-env.mjs`, `healthcheck.mjs`, + `system-info.mjs`. +- **`scripts/check/`** — `check-cycles.mjs`, `check-docs-sync.mjs`, + `check-docs-counts-sync.mjs`, `check-env-doc-sync.mjs`, + `check-deprecated-versions.mjs`, `check-route-validation.mjs`, + `check-t11-any-budget.mjs`, `check-pr-test-policy.mjs`, + `check-supported-node-runtime.ts`, `test-report-summary.mjs`. +- **`scripts/docs/`** — `generate-docs-index.mjs`, `gen-provider-reference.ts`. +- **`scripts/i18n/`** — `generate-multilang.mjs`, `run-visual-qa.mjs`, + `generate-qa-checklist.mjs`, `apply-priority-overrides.mjs`, + `validate_translation.py`, `check_translations.py`, `i18n_autotranslate.py`, + `untranslatable-keys.json`. +- **`scripts/ad-hoc/`** — `cursor-tap.cjs`, `sync-cursor-models.mjs`, + `migrate-env.mjs`, `dbsetup.js`. --- diff --git a/docs/COVERAGE_PLAN.md b/docs/COVERAGE_PLAN.md index 7829d8d1c3..9ef6e19962 100644 --- a/docs/COVERAGE_PLAN.md +++ b/docs/COVERAGE_PLAN.md @@ -156,7 +156,7 @@ Update `npm run test:coverage` thresholds only after the project actually exceed For ad-hoc threshold checks against the latest report use: ```bash -node scripts/test-report-summary.mjs --threshold 75 +node scripts/check/test-report-summary.mjs --threshold 75 ``` Recommended ratchet sequence (order is `statements-lines / branches / functions`): diff --git a/docs/ELECTRON_GUIDE.md b/docs/ELECTRON_GUIDE.md index d5ad443a4a..0892a8f1d6 100644 --- a/docs/ELECTRON_GUIDE.md +++ b/docs/ELECTRON_GUIDE.md @@ -56,7 +56,7 @@ Confirmed from `electron/package.json`: The `electron/` workspace also exposes: -- `npm run prepare:bundle` — runs `scripts/prepare-electron-standalone.mjs` +- `npm run prepare:bundle` — runs `scripts/build/prepare-electron-standalone.mjs` - `npm run build:mac-x64` / `build:mac-arm64` — single-arch macOS builds - `npm run pack` — directory-only build for local testing (no installer) @@ -73,8 +73,10 @@ electron/ └── dist-electron/ # electron-builder output (gitignored) scripts/ -├── prepare-electron-standalone.mjs # Stages .next/electron-standalone bundle -└── smoke-electron-packaged.mjs # Post-build smoke test +├── build/ +│ └── prepare-electron-standalone.mjs # Stages .next/electron-standalone bundle +└── dev/ + └── smoke-electron-packaged.mjs # Post-build smoke test ``` Both `main.js` and `preload.js` are **CommonJS `.js` files**, not TypeScript. The @@ -202,7 +204,7 @@ NSIS settings: `oneClick: false`, lets the user choose the install directory, cr npm run electron:smoke:packaged ``` -`scripts/smoke-electron-packaged.mjs`: +`scripts/dev/smoke-electron-packaged.mjs`: - Auto-discovers the packaged binary in `electron/dist-electron/` for the current platform. - Launches with isolated `HOME`/`APPDATA`/`XDG_*` directories so it doesn't touch developer data. @@ -266,4 +268,4 @@ Releases are published to GitHub Releases (`diegosouzapw/OmniRoute`), which is a - [SETUP_GUIDE.md](./SETUP_GUIDE.md) - [RELEASE_CHECKLIST.md](./RELEASE_CHECKLIST.md) - Source: `electron/main.js`, `electron/preload.js`, `electron/package.json` -- Helpers: `scripts/prepare-electron-standalone.mjs`, `scripts/smoke-electron-packaged.mjs` +- Helpers: `scripts/build/prepare-electron-standalone.mjs`, `scripts/dev/smoke-electron-packaged.mjs` diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 0087bb2ee0..71bb4a8f7f 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -66,19 +66,19 @@ echo "OMNIROUTE_WS_BRIDGE_SECRET=$(openssl rand -base64 32)" OmniRoute uses **SQLite** (via `better-sqlite3`) for all persistence. These variables control data location, encryption, and lifecycle. -| Variable | Default | Source File | Description | -| -------------------------------------- | -------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `DATA_DIR` | `~/.omniroute/` | `src/lib/db/core.ts` | Root directory for SQLite DB, backups, and data files. Override for Docker volumes or custom paths. | -| `STORAGE_ENCRYPTION_KEY` | _(empty = disabled)_ | `src/lib/db/encryption.ts` | AES key for full SQLite database encryption at rest. Generate with `openssl rand -hex 32`. | -| `STORAGE_ENCRYPTION_KEY_VERSION` | `v1` | `scripts/bootstrap-env.mjs`, `electron/main.js` | Version label for the encryption key. Increment when performing key rotation to support decryption of old backups. | -| `DISABLE_SQLITE_AUTO_BACKUP` | `false` | `src/lib/db/backup.ts` | When `true`, skips the automatic database backup that runs before migrations on every startup. | -| `OMNIROUTE_CRYPT_KEY` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** for `STORAGE_ENCRYPTION_KEY`. Accepted as a fallback when the primary variable is absent. | -| `OMNIROUTE_API_KEY_BASE64` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** (Base64-encoded form) accepted as a fallback. Decoded automatically before use. | -| `OMNIROUTE_DB_HEALTHCHECK_INTERVAL_MS` | _(unset)_ | `src/lib/db/core.ts` | Override the periodic SQLite healthcheck interval (ms). When unset, defaults are derived from `NODE_ENV`. | -| `OMNIROUTE_FORCE_DB_HEALTHCHECK` | `0` | `src/lib/db/core.ts` | Set to `1` to force the DB healthcheck loop on, even when it would normally be skipped (e.g., short-lived tasks). | -| `OMNIROUTE_MIGRATIONS_DIR` | _(auto-detect)_ | `src/lib/db/migrationRunner.ts` | Override the directory that the migration runner scans. Useful when shipping bundled migrations in custom builds. | -| `OMNIROUTE_SPEND_FLUSH_INTERVAL_MS` | _(default in code)_ | `src/lib/spend/batchWriter.ts` | Flush interval (ms) for the batched spend/cost writer. Lower values reduce write coalescing; higher values reduce DB contention. | -| `OMNIROUTE_SPEND_MAX_BUFFER_SIZE` | _(default in code)_ | `src/lib/spend/batchWriter.ts` | Max buffered spend entries before a forced flush. Raise on high-QPS deployments; lower when bounded memory matters more. | +| Variable | Default | Source File | Description | +| -------------------------------------- | -------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `DATA_DIR` | `~/.omniroute/` | `src/lib/db/core.ts` | Root directory for SQLite DB, backups, and data files. Override for Docker volumes or custom paths. | +| `STORAGE_ENCRYPTION_KEY` | _(empty = disabled)_ | `src/lib/db/encryption.ts` | AES key for full SQLite database encryption at rest. Generate with `openssl rand -hex 32`. | +| `STORAGE_ENCRYPTION_KEY_VERSION` | `v1` | `scripts/build/bootstrap-env.mjs`, `electron/main.js` | Version label for the encryption key. Increment when performing key rotation to support decryption of old backups. | +| `DISABLE_SQLITE_AUTO_BACKUP` | `false` | `src/lib/db/backup.ts` | When `true`, skips the automatic database backup that runs before migrations on every startup. | +| `OMNIROUTE_CRYPT_KEY` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** for `STORAGE_ENCRYPTION_KEY`. Accepted as a fallback when the primary variable is absent. | +| `OMNIROUTE_API_KEY_BASE64` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** (Base64-encoded form) accepted as a fallback. Decoded automatically before use. | +| `OMNIROUTE_DB_HEALTHCHECK_INTERVAL_MS` | _(unset)_ | `src/lib/db/core.ts` | Override the periodic SQLite healthcheck interval (ms). When unset, defaults are derived from `NODE_ENV`. | +| `OMNIROUTE_FORCE_DB_HEALTHCHECK` | `0` | `src/lib/db/core.ts` | Set to `1` to force the DB healthcheck loop on, even when it would normally be skipped (e.g., short-lived tasks). | +| `OMNIROUTE_MIGRATIONS_DIR` | _(auto-detect)_ | `src/lib/db/migrationRunner.ts` | Override the directory that the migration runner scans. Useful when shipping bundled migrations in custom builds. | +| `OMNIROUTE_SPEND_FLUSH_INTERVAL_MS` | _(default in code)_ | `src/lib/spend/batchWriter.ts` | Flush interval (ms) for the batched spend/cost writer. Lower values reduce write coalescing; higher values reduce DB contention. | +| `OMNIROUTE_SPEND_MAX_BUFFER_SIZE` | _(default in code)_ | `src/lib/spend/batchWriter.ts` | Max buffered spend entries before a forced flush. Raise on high-QPS deployments; lower when bounded memory matters more. | ### Scenarios diff --git a/docs/FEATURES.md b/docs/FEATURES.md index a38213546a..d4bab1d197 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -269,7 +269,7 @@ Key features: ## 🌐 V1 WebSocket Bridge _(v3.6.6+)_ -OmniRoute now supports **OpenAI-compatible WebSocket clients** via the `/v1/ws` upgrade endpoint. The custom `scripts/v1-ws-bridge.mjs` server wraps Next.js and upgrades WS connections to full bidirectional streaming sessions. Authentication uses the same API key or session cookie as HTTP requests. +OmniRoute now supports **OpenAI-compatible WebSocket clients** via the `/v1/ws` upgrade endpoint. The custom `scripts/dev/v1-ws-bridge.mjs` server wraps Next.js and upgrades WS connections to full bidirectional streaming sessions. Authentication uses the same API key or session cookie as HTTP requests. Key behaviours: diff --git a/docs/I18N.md b/docs/I18N.md index 458e5df371..c14b71a98a 100644 --- a/docs/I18N.md +++ b/docs/I18N.md @@ -6,14 +6,14 @@ OmniRoute supports **30 languages** with full dashboard UI translation, translat ## Quick Reference -| Task | Command | -| ---------------------- | --------------------------------------------------------------------------------------- | -| Generate translations | `node scripts/i18n/generate-multilang.mjs messages` | -| Translate docs (LLM) | `python3 scripts/i18n_autotranslate.py --api-url --api-key --model ` | -| Validate a locale | `python3 scripts/validate_translation.py quick -l cs` | -| Check code keys | `python3 scripts/check_translations.py` | -| Generate QA report | `node scripts/i18n/generate-qa-checklist.mjs` | -| Visual QA (Playwright) | `node scripts/i18n/run-visual-qa.mjs` | +| Task | Command | +| ---------------------- | -------------------------------------------------------------------------------------------- | +| Generate translations | `node scripts/i18n/generate-multilang.mjs messages` | +| Translate docs (LLM) | `python3 scripts/i18n/i18n_autotranslate.py --api-url --api-key --model ` | +| Validate a locale | `python3 scripts/i18n/validate_translation.py quick -l cs` | +| Check code keys | `python3 scripts/i18n/check_translations.py` | +| Generate QA report | `node scripts/i18n/generate-qa-checklist.mjs` | +| Visual QA (Playwright) | `node scripts/i18n/run-visual-qa.mjs` | ## Architecture @@ -115,8 +115,8 @@ Auto-translations are a starting point. Review manually for: ### 5. Validate ```bash -python3 scripts/validate_translation.py quick -l xx -python3 scripts/validate_translation.py diff common -l xx +python3 scripts/i18n/validate_translation.py quick -l xx +python3 scripts/i18n/validate_translation.py diff common -l xx ``` ### 6. Generate Translated Documentation @@ -162,7 +162,7 @@ node scripts/i18n/generate-multilang.mjs [messages|readme|docs|all] **Secondary translator** — uses any OpenAI-compatible LLM API (including OmniRoute itself) to translate existing `docs/i18n/` markdown files. Best for polishing or re-translating docs with better quality than Google Translate. ```bash -python3 scripts/i18n_autotranslate.py \ +python3 scripts/i18n/i18n_autotranslate.py \ --api-url http://localhost:20128/v1 \ --api-key sk-your-key \ --model gpt-4o @@ -183,24 +183,24 @@ python3 scripts/i18n_autotranslate.py \ ```bash # Quick check (counts only) -python3 scripts/validate_translation.py quick -l cs +python3 scripts/i18n/validate_translation.py quick -l cs # Output: # Missing: 0 # Untranslated: 0 # Ignored (UNTRANSLATABLE_KEYS): 236 # Detailed diff by category -python3 scripts/validate_translation.py diff common -l cs -python3 scripts/validate_translation.py diff settings -l cs +python3 scripts/i18n/validate_translation.py diff common -l cs +python3 scripts/i18n/validate_translation.py diff settings -l cs # Export to CSV -python3 scripts/validate_translation.py csv -l cs > report.csv +python3 scripts/i18n/validate_translation.py csv -l cs > report.csv # Export to Markdown -python3 scripts/validate_translation.py md -l cs > report.md +python3 scripts/i18n/validate_translation.py md -l cs > report.md # Full report (default) -python3 scripts/validate_translation.py -l cs +python3 scripts/i18n/validate_translation.py -l cs ``` **Detects:** @@ -226,13 +226,13 @@ python3 scripts/validate_translation.py -l cs ```bash # Basic check -python3 scripts/check_translations.py +python3 scripts/i18n/check_translations.py # Verbose output -python3 scripts/check_translations.py --verbose +python3 scripts/i18n/check_translations.py --verbose # Auto-fix (adds missing keys to en.json) -python3 scripts/check_translations.py --fix +python3 scripts/i18n/check_translations.py --fix ``` ### generate-qa-checklist.mjs @@ -322,7 +322,7 @@ The CI pipeline validates all locales on every push and PR: LANGS=$(ls src/i18n/messages/*.json | xargs -n1 basename | sed 's/.json$//' | grep -v '^en$') # i18n: validates each language -python3 scripts/validate_translation.py quick -l '${{ matrix.lang }}' +python3 scripts/i18n/validate_translation.py quick -l '${{ matrix.lang }}' ``` **Dashboard output:** @@ -384,7 +384,7 @@ docs/ 1. **Always edit `en.json` first** — it's the source of truth 2. **Run `generate-multilang.mjs messages`** to propagate new keys to all locales 3. **Review auto-translations** — Google Translate is a starting point, not final -4. **Validate before committing** — `python3 scripts/validate_translation.py quick -l ` +4. **Validate before committing** — `python3 scripts/i18n/validate_translation.py quick -l ` 5. **Update `untranslatable-keys.json`** if a key should remain in English ### Placeholder Safety @@ -401,7 +401,7 @@ const t = useTranslations("settings"); t("cacheSettings"); // maps to settings.cacheSettings in JSON // Run check_translations.py to verify keys exist -python3 scripts/check_translations.py --verbose +python3 scripts/i18n/check_translations.py --verbose ``` ### RTL Considerations diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md index 142d992f15..bb450c9b6b 100644 --- a/docs/RELEASE_CHECKLIST.md +++ b/docs/RELEASE_CHECKLIST.md @@ -72,7 +72,7 @@ npm run test:e2e # optional but recommended Husky hooks live in `.husky/` and run automatically on git operations. -- **pre-commit:** `npx lint-staged + node scripts/check-docs-sync.mjs + npm run check:any-budget:t11` +- **pre-commit:** `npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11` - **pre-push:** currently disabled (commented out). When re-enabled, runs `npm run test:unit`. - Run `npm run test:unit` manually before pushing release branches. diff --git a/electron/package.json b/electron/package.json index 17954f3c5b..ed9bd461bf 100644 --- a/electron/package.json +++ b/electron/package.json @@ -12,7 +12,7 @@ "scripts": { "start": "electron .", "dev": "electron . --no-sandbox", - "prepare:bundle": "node ../scripts/prepare-electron-standalone.mjs", + "prepare:bundle": "node ../scripts/build/prepare-electron-standalone.mjs", "build": "npm run prepare:bundle && electron-builder", "build:win": "npm run prepare:bundle && electron-builder --win", "build:mac": "npm run prepare:bundle && electron-builder --mac", @@ -26,7 +26,7 @@ "electron-updater": "^6.8.5" }, "devDependencies": { -"electron": "^42.0.1", + "electron": "^42.0.1", "electron-builder": "^26.10.0" }, "overrides": { diff --git a/package.json b/package.json index 03cee3da5f..33055ac46f 100644 --- a/package.json +++ b/package.json @@ -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,59 +61,59 @@ }, "homepage": "https://omniroute.online", "scripts": { - "dev": "node scripts/run-next.mjs dev", - "prebuild:docs": "node scripts/generate-docs-index.mjs", - "gen:provider-reference": "node --import tsx/esm scripts/gen-provider-reference.ts", - "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", + "gen:provider-reference": "node --import tsx/esm scripts/docs/gen-provider-reference.ts", + "build": "node scripts/build/build-next-isolated.mjs", + "build:cli": "node --import tsx/esm 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", + "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", - "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:env-doc-sync": "node scripts/check-env-doc-sync.mjs", - "check:docs-counts": "node scripts/check-docs-counts-sync.mjs", - "check:deprecated-versions": "node scripts/check-deprecated-versions.mjs", + "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:env-doc-sync": "node scripts/check/check-env-doc-sync.mjs", + "check:docs-counts": "node scripts/check/check-docs-counts-sync.mjs", + "check:deprecated-versions": "node scripts/check/check-deprecated-versions.mjs", "check:docs-all": "npm run check:docs-sync && npm run check:docs-counts && npm run check:env-doc-sync && npm run check:deprecated-versions", - "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", + "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", "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", + "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:e2e": "node scripts/run-playwright-tests.mjs test tests/e2e/*.spec.ts", - "test:protocols:e2e": "node scripts/run-protocol-clients-tests.mjs", + "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: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", "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", @@ -128,7 +128,7 @@ "express": "^5.2.1", "fetch-socks": "^1.3.3", "fuse.js": "^7.3.0", -"gray-matter": "^4.0.3", + "gray-matter": "^4.0.3", "http-proxy-middleware": "^4.0.0", "https-proxy-agent": "^9.0.0", "ioredis": "^5.10.1", diff --git a/playwright.config.ts b/playwright.config.ts index 624fc5a6b1..8e6b6f893e 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -34,7 +34,7 @@ export default defineConfig({ }, ], webServer: { - command: `${JSON.stringify(process.execPath)} scripts/run-next-playwright.mjs ${playwrightServerMode}`, + command: `${JSON.stringify(process.execPath)} scripts/dev/run-next-playwright.mjs ${playwrightServerMode}`, url: webServerReadyUrl, reuseExistingServer: !process.env.CI, timeout: Number.isFinite(playwrightWebServerTimeout) ? playwrightWebServerTimeout : 900_000, diff --git a/scripts/cursor-tap.cjs b/scripts/ad-hoc/cursor-tap.cjs similarity index 97% rename from scripts/cursor-tap.cjs rename to scripts/ad-hoc/cursor-tap.cjs index 1c0e548699..5f0304aa67 100644 --- a/scripts/cursor-tap.cjs +++ b/scripts/ad-hoc/cursor-tap.cjs @@ -142,7 +142,7 @@ req.on("data", (chunk) => { }); req.on("end", () => { const raw = Buffer.concat(collected); - const outDir = path.join(__dirname, "..", "tests", "fixtures", "cursor"); + const outDir = path.join(__dirname, "..", "..", "tests", "fixtures", "cursor"); fs.mkdirSync(outDir, { recursive: true }); const outFile = path.join(outDir, `${fixtureName}.bin`); fs.writeFileSync(outFile, raw); @@ -168,7 +168,7 @@ setTimeout(() => { } catch {} const raw = Buffer.concat(collected); if (raw.length > 0) { - const outDir = path.join(__dirname, "..", "tests", "fixtures", "cursor"); + const outDir = path.join(__dirname, "..", "..", "tests", "fixtures", "cursor"); fs.mkdirSync(outDir, { recursive: true }); fs.writeFileSync(path.join(outDir, `${fixtureName}.bin`), raw); } diff --git a/scripts/dbsetup.js b/scripts/ad-hoc/dbsetup.js similarity index 100% rename from scripts/dbsetup.js rename to scripts/ad-hoc/dbsetup.js diff --git a/scripts/migrate-env.mjs b/scripts/ad-hoc/migrate-env.mjs similarity index 100% rename from scripts/migrate-env.mjs rename to scripts/ad-hoc/migrate-env.mjs diff --git a/scripts/sync-cursor-models.mjs b/scripts/ad-hoc/sync-cursor-models.mjs similarity index 93% rename from scripts/sync-cursor-models.mjs rename to scripts/ad-hoc/sync-cursor-models.mjs index 7aa29a88e8..48698d016a 100644 --- a/scripts/sync-cursor-models.mjs +++ b/scripts/ad-hoc/sync-cursor-models.mjs @@ -4,9 +4,9 @@ // invocation so cursor-agent prints "Available models: ..." on stderr. // // Usage: -// node scripts/sync-cursor-models.mjs # spawn cursor-agent and apply -// node scripts/sync-cursor-models.mjs --dry-run # print proposed block, don't write -// node scripts/sync-cursor-models.mjs --from-stdin # read the error message from stdin +// node scripts/ad-hoc/sync-cursor-models.mjs # spawn cursor-agent and apply +// node scripts/ad-hoc/sync-cursor-models.mjs --dry-run # print proposed block, don't write +// node scripts/ad-hoc/sync-cursor-models.mjs --from-stdin # read the error message from stdin import { spawnSync } from "node:child_process"; import { readFileSync, writeFileSync } from "node:fs"; diff --git a/scripts/bootstrap-env.mjs b/scripts/build/bootstrap-env.mjs similarity index 99% rename from scripts/bootstrap-env.mjs rename to scripts/build/bootstrap-env.mjs index 06e5deaad2..c39e9b9107 100644 --- a/scripts/bootstrap-env.mjs +++ b/scripts/build/bootstrap-env.mjs @@ -312,7 +312,7 @@ export function bootstrapEnv({ dataDirOverride, quiet = false } = {}) { return merged; } -// ── CLI usage: node scripts/bootstrap-env.mjs ────────────────────────────── +// ── CLI usage: node scripts/build/bootstrap-env.mjs ────────────────────────────── if (process.argv[1] && process.argv[1].endsWith("bootstrap-env.mjs")) { const env = bootstrapEnv(); process.stderr.write(`[bootstrap] Done. DATA_DIR resolved to: ${resolveDataDir()}\n`); diff --git a/scripts/build-next-isolated.mjs b/scripts/build/build-next-isolated.mjs similarity index 98% rename from scripts/build-next-isolated.mjs rename to scripts/build/build-next-isolated.mjs index 88e1ffacab..e9969c3a06 100644 --- a/scripts/build-next-isolated.mjs +++ b/scripts/build/build-next-isolated.mjs @@ -187,7 +187,7 @@ export async function main() { console.log("[build-next-isolated] Generating docs index..."); try { const { execSync } = await import("node:child_process"); - execSync("node scripts/generate-docs-index.mjs", { cwd: projectRoot, stdio: "inherit" }); + execSync("node scripts/docs/generate-docs-index.mjs", { cwd: projectRoot, stdio: "inherit" }); } catch (docGenErr) { console.warn( "[build-next-isolated] Docs index generation failed (non-fatal):", diff --git a/scripts/native-binary-compat.mjs b/scripts/build/native-binary-compat.mjs similarity index 100% rename from scripts/native-binary-compat.mjs rename to scripts/build/native-binary-compat.mjs diff --git a/scripts/pack-artifact-policy.ts b/scripts/build/pack-artifact-policy.ts similarity index 90% rename from scripts/pack-artifact-policy.ts rename to scripts/build/pack-artifact-policy.ts index 5417abecce..2a78ec3fce 100644 --- a/scripts/pack-artifact-policy.ts +++ b/scripts/build/pack-artifact-policy.ts @@ -33,7 +33,7 @@ export const APP_STAGING_ALLOWED_EXACT_PATHS: string[] = [ "open-sse/mcp-server/server.js", "package.json", "responses-ws-proxy.mjs", - "scripts/sync-env.mjs", + "scripts/dev/sync-env.mjs", "server.js", "server-ws.mjs", ]; @@ -74,13 +74,13 @@ export const PACK_ARTIFACT_ROOT_ALLOWED_EXACT_PATHS: string[] = [ "open-sse/mcp-server/scopeEnforcement.ts", "open-sse/mcp-server/server.ts", "package.json", - "scripts/build-next-isolated.mjs", - "scripts/check-supported-node-runtime.ts", - "scripts/native-binary-compat.mjs", - "scripts/postinstall.mjs", - "scripts/postinstallSupport.mjs", - "scripts/responses-ws-proxy.mjs", - "scripts/sync-env.mjs", + "scripts/build/build-next-isolated.mjs", + "scripts/check/check-supported-node-runtime.ts", + "scripts/build/native-binary-compat.mjs", + "scripts/build/postinstall.mjs", + "scripts/build/postinstallSupport.mjs", + "scripts/dev/responses-ws-proxy.mjs", + "scripts/dev/sync-env.mjs", "src/shared/utils/nodeRuntimeSupport.ts", ]; @@ -103,9 +103,9 @@ export const PACK_ARTIFACT_REQUIRED_PATHS: string[] = [ "bin/nodeRuntimeSupport.mjs", "bin/omniroute.mjs", "package.json", - "scripts/native-binary-compat.mjs", - "scripts/postinstall.mjs", - "scripts/postinstallSupport.mjs", + "scripts/build/native-binary-compat.mjs", + "scripts/build/postinstall.mjs", + "scripts/build/postinstallSupport.mjs", "src/shared/utils/nodeRuntimeSupport.ts", ]; diff --git a/scripts/postinstall.mjs b/scripts/build/postinstall.mjs similarity index 99% rename from scripts/postinstall.mjs rename to scripts/build/postinstall.mjs index a9ef2689df..210b18388f 100644 --- a/scripts/postinstall.mjs +++ b/scripts/build/postinstall.mjs @@ -31,7 +31,7 @@ import { hasStandaloneAppBundle } from "./postinstallSupport.mjs"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const ROOT = join(__dirname, ".."); +const ROOT = join(__dirname, "..", ".."); const appBinary = join( ROOT, diff --git a/scripts/postinstallSupport.mjs b/scripts/build/postinstallSupport.mjs similarity index 100% rename from scripts/postinstallSupport.mjs rename to scripts/build/postinstallSupport.mjs diff --git a/scripts/prepare-electron-standalone.mjs b/scripts/build/prepare-electron-standalone.mjs similarity index 99% rename from scripts/prepare-electron-standalone.mjs rename to scripts/build/prepare-electron-standalone.mjs index 30647e2b03..a91eac08ac 100644 --- a/scripts/prepare-electron-standalone.mjs +++ b/scripts/build/prepare-electron-standalone.mjs @@ -15,7 +15,7 @@ import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const ROOT = join(__dirname, ".."); +const ROOT = join(__dirname, "..", ".."); const STANDALONE_DIR = join(ROOT, ".next", "standalone"); const ELECTRON_STANDALONE_DIR = join(ROOT, ".next", "electron-standalone"); diff --git a/scripts/prepublish.ts b/scripts/build/prepublish.ts similarity index 98% rename from scripts/prepublish.ts rename to scripts/build/prepublish.ts index 819e1dd2b1..c784076e3c 100644 --- a/scripts/prepublish.ts +++ b/scripts/build/prepublish.ts @@ -6,7 +6,7 @@ * Builds the Next.js app in standalone mode and copies output * into the `app/` directory that gets published to npm. * - * Run with: node scripts/prepublish.mjs + * Run with: node scripts/build/prepublish.ts */ import { execFileSync } from "node:child_process"; @@ -33,7 +33,7 @@ import { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const ROOT = join(__dirname, ".."); +const ROOT = join(__dirname, "..", ".."); const NPM_BIN = process.platform === "win32" ? "npm.cmd" : "npm"; const NPX_BIN = process.platform === "win32" ? "npx.cmd" : "npx"; @@ -200,14 +200,14 @@ console.log(" 📋 Copying standalone build to app/..."); mkdirSync(APP_DIR, { recursive: true }); cpSync(standaloneDir, APP_DIR, { recursive: true }); -const standaloneWsSrc = join(ROOT, "scripts", "standalone-server-ws.mjs"); -const responsesWsProxySrc = join(ROOT, "scripts", "responses-ws-proxy.mjs"); +const standaloneWsSrc = join(ROOT, "scripts", "dev", "standalone-server-ws.mjs"); +const responsesWsProxySrc = join(ROOT, "scripts", "dev", "responses-ws-proxy.mjs"); if (existsSync(standaloneWsSrc) && existsSync(responsesWsProxySrc)) { console.log(" 📋 Adding Responses WebSocket standalone wrapper..."); cpSync(standaloneWsSrc, join(APP_DIR, "server-ws.mjs")); writeFileSync( join(APP_DIR, "responses-ws-proxy.mjs"), - 'export * from "../scripts/responses-ws-proxy.mjs";\n' + 'export * from "../scripts/dev/responses-ws-proxy.mjs";\n' ); } diff --git a/scripts/runtime-env.mjs b/scripts/build/runtime-env.mjs similarity index 100% rename from scripts/runtime-env.mjs rename to scripts/build/runtime-env.mjs diff --git a/scripts/uninstall.mjs b/scripts/build/uninstall.mjs similarity index 100% rename from scripts/uninstall.mjs rename to scripts/build/uninstall.mjs diff --git a/scripts/validate-pack-artifact.ts b/scripts/build/validate-pack-artifact.ts similarity index 98% rename from scripts/validate-pack-artifact.ts rename to scripts/build/validate-pack-artifact.ts index afaaa20761..2053fd69b1 100644 --- a/scripts/validate-pack-artifact.ts +++ b/scripts/build/validate-pack-artifact.ts @@ -14,7 +14,7 @@ import { const __filename: string = fileURLToPath(import.meta.url); const __dirname: string = dirname(__filename); -const ROOT: string = join(__dirname, ".."); +const ROOT: string = join(__dirname, "..", ".."); const npmCommand: string = process.platform === "win32" ? "npm.cmd" : "npm"; function runPackDryRun(): any { diff --git a/scripts/check-cycles.mjs b/scripts/check/check-cycles.mjs similarity index 100% rename from scripts/check-cycles.mjs rename to scripts/check/check-cycles.mjs diff --git a/scripts/check-deprecated-versions.mjs b/scripts/check/check-deprecated-versions.mjs similarity index 95% rename from scripts/check-deprecated-versions.mjs rename to scripts/check/check-deprecated-versions.mjs index 990db76fe0..fda48e663b 100644 --- a/scripts/check-deprecated-versions.mjs +++ b/scripts/check/check-deprecated-versions.mjs @@ -3,15 +3,15 @@ // Uses hardcoded regexes to avoid dynamic RegExp() (ReDoS concern flagged by semgrep). // Exits 0 if clean, 1 (in --strict mode) if drift detected. // -// Run: node scripts/check-deprecated-versions.mjs -// Strict: node scripts/check-deprecated-versions.mjs --strict +// Run: node scripts/check/check-deprecated-versions.mjs +// Strict: node scripts/check/check-deprecated-versions.mjs --strict import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT = path.resolve(__dirname, ".."); +const ROOT = path.resolve(__dirname, "..", ".."); const DOCS_DIR = path.join(ROOT, "docs"); const PKG_JSON = path.join(ROOT, "package.json"); const STRICT = process.argv.includes("--strict"); diff --git a/scripts/check-docs-counts-sync.mjs b/scripts/check/check-docs-counts-sync.mjs similarity index 96% rename from scripts/check-docs-counts-sync.mjs rename to scripts/check/check-docs-counts-sync.mjs index 833d52c5a5..7f84a1a784 100644 --- a/scripts/check-docs-counts-sync.mjs +++ b/scripts/check/check-docs-counts-sync.mjs @@ -8,14 +8,14 @@ // - Cloud agents in src/lib/cloudAgent/agents/ // // Exits 0 on success, 1 on detected drift. -// Run: node scripts/check-docs-counts-sync.mjs +// Run: node scripts/check/check-docs-counts-sync.mjs import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT = path.resolve(__dirname, ".."); +const ROOT = path.resolve(__dirname, "..", ".."); const COMMON_NON_IMPL_BASENAMES = new Set([ "index.ts", diff --git a/scripts/check-docs-sync.mjs b/scripts/check/check-docs-sync.mjs similarity index 100% rename from scripts/check-docs-sync.mjs rename to scripts/check/check-docs-sync.mjs diff --git a/scripts/check-env-doc-sync.mjs b/scripts/check/check-env-doc-sync.mjs similarity index 96% rename from scripts/check-env-doc-sync.mjs rename to scripts/check/check-env-doc-sync.mjs index 8f03665604..eeb9db8114 100644 --- a/scripts/check-env-doc-sync.mjs +++ b/scripts/check/check-env-doc-sync.mjs @@ -2,8 +2,8 @@ // Validates that env vars referenced in code appear in .env.example AND in docs/ENVIRONMENT.md. // Exits 0 on success, 1 on missing entries. Designed for use in pre-commit / CI. // -// Run: node scripts/check-env-doc-sync.mjs -// Strict mode: node scripts/check-env-doc-sync.mjs --strict +// Run: node scripts/check/check-env-doc-sync.mjs +// Strict mode: node scripts/check/check-env-doc-sync.mjs --strict // In strict mode, missing entries cause failure. In default mode, only summary is printed. import fs from "node:fs"; @@ -12,7 +12,7 @@ import { fileURLToPath } from "node:url"; import { execSync } from "node:child_process"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT = path.resolve(__dirname, ".."); +const ROOT = path.resolve(__dirname, "..", ".."); const ENV_EXAMPLE = path.join(ROOT, ".env.example"); const ENV_DOC = path.join(ROOT, "docs", "ENVIRONMENT.md"); diff --git a/scripts/check-pr-test-policy.mjs b/scripts/check/check-pr-test-policy.mjs similarity index 90% rename from scripts/check-pr-test-policy.mjs rename to scripts/check/check-pr-test-policy.mjs index ae7160f2e9..de33e8babf 100644 --- a/scripts/check-pr-test-policy.mjs +++ b/scripts/check/check-pr-test-policy.mjs @@ -6,14 +6,17 @@ const SOURCE_ROOTS = ["src/", "open-sse/", "electron/", "bin/"]; const TEST_PATTERNS = [/^tests\//, /(?:^|\/)__tests__\//, /\.(?:test|spec)\.[cm]?[jt]sx?$/]; // Test files for specific source types (e.g., Python validation scripts for i18n) const TEST_FILE_PATTERNS = { - "src/i18n/messages/": [/\/scripts\/validate_translation\.py$/, /\/scripts\/check_translations\.py$/], + "src/i18n/messages/": [ + /\/scripts\/validate_translation\.py$/, + /\/scripts\/check_translations\.py$/, + ], }; // Exclude directories that don't require tests (i18n has Python validation, docs, config) const EXCLUDED_PATTERNS = [ - /\/i18n\/messages\//, // i18n files have their own Python test scripts - /\.md$/, // Documentation - /\.yaml$/, // Config files - /\.yml$/, // Config files + /\/i18n\/messages\//, // i18n files have their own Python test scripts + /\.md$/, // Documentation + /\.yaml$/, // Config files + /\.yml$/, // Config files ]; function getArg(name, fallbackValue = "") { @@ -30,7 +33,7 @@ function runGit(args) { function isSourceFile(filePath) { // Exclude patterns that don't require tests - if (EXCLUDED_PATTERNS.some(pattern => pattern.test(filePath))) { + if (EXCLUDED_PATTERNS.some((pattern) => pattern.test(filePath))) { return false; } return SOURCE_ROOTS.some((root) => filePath.startsWith(root)); diff --git a/scripts/check-route-validation.mjs b/scripts/check/check-route-validation.mjs similarity index 100% rename from scripts/check-route-validation.mjs rename to scripts/check/check-route-validation.mjs diff --git a/scripts/check-supported-node-runtime.ts b/scripts/check/check-supported-node-runtime.ts similarity index 91% rename from scripts/check-supported-node-runtime.ts rename to scripts/check/check-supported-node-runtime.ts index 977a84a5ab..197966822e 100644 --- a/scripts/check-supported-node-runtime.ts +++ b/scripts/check/check-supported-node-runtime.ts @@ -3,7 +3,7 @@ import { getNodeRuntimeSupport, getNodeRuntimeWarning, -} from "../src/shared/utils/nodeRuntimeSupport.ts"; +} from "../../src/shared/utils/nodeRuntimeSupport.ts"; const support = getNodeRuntimeSupport(); diff --git a/scripts/check-t11-any-budget.mjs b/scripts/check/check-t11-any-budget.mjs similarity index 100% rename from scripts/check-t11-any-budget.mjs rename to scripts/check/check-t11-any-budget.mjs diff --git a/scripts/test-report-summary.mjs b/scripts/check/test-report-summary.mjs similarity index 100% rename from scripts/test-report-summary.mjs rename to scripts/check/test-report-summary.mjs diff --git a/scripts/healthcheck.mjs b/scripts/dev/healthcheck.mjs similarity index 100% rename from scripts/healthcheck.mjs rename to scripts/dev/healthcheck.mjs diff --git a/scripts/responses-ws-proxy.mjs b/scripts/dev/responses-ws-proxy.mjs similarity index 100% rename from scripts/responses-ws-proxy.mjs rename to scripts/dev/responses-ws-proxy.mjs diff --git a/scripts/run-ecosystem-tests.mjs b/scripts/dev/run-ecosystem-tests.mjs similarity index 97% rename from scripts/run-ecosystem-tests.mjs rename to scripts/dev/run-ecosystem-tests.mjs index 93db56ea31..8294d8ca1e 100644 --- a/scripts/run-ecosystem-tests.mjs +++ b/scripts/dev/run-ecosystem-tests.mjs @@ -3,7 +3,7 @@ import { spawn } from "node:child_process"; import { join } from "node:path"; import { setTimeout as delay } from "node:timers/promises"; -import { sanitizeColorEnv } from "./runtime-env.mjs"; +import { sanitizeColorEnv } from "../build/runtime-env.mjs"; function parsePort(value, fallback) { const parsed = Number.parseInt(String(value), 10); diff --git a/scripts/run-next-playwright.mjs b/scripts/dev/run-next-playwright.mjs similarity index 98% rename from scripts/run-next-playwright.mjs rename to scripts/dev/run-next-playwright.mjs index fad1ae20a5..84673696ef 100644 --- a/scripts/run-next-playwright.mjs +++ b/scripts/dev/run-next-playwright.mjs @@ -9,8 +9,8 @@ import { sanitizeColorEnv, spawnWithForwardedSignals, withRuntimePortEnv, -} from "./runtime-env.mjs"; -import { bootstrapEnv } from "./bootstrap-env.mjs"; +} from "../build/runtime-env.mjs"; +import { bootstrapEnv } from "../build/bootstrap-env.mjs"; const mode = process.argv[2] === "start" ? "start" : "dev"; const cwd = process.cwd(); diff --git a/scripts/run-next.mjs b/scripts/dev/run-next.mjs similarity index 96% rename from scripts/run-next.mjs rename to scripts/dev/run-next.mjs index 293a38f165..1a108d40d2 100644 --- a/scripts/run-next.mjs +++ b/scripts/dev/run-next.mjs @@ -4,8 +4,8 @@ import fs from "node:fs"; import http from "node:http"; import path from "node:path"; import next from "next"; -import { bootstrapEnv } from "./bootstrap-env.mjs"; -import { resolveRuntimePorts, withRuntimePortEnv } from "./runtime-env.mjs"; +import { bootstrapEnv } from "../build/bootstrap-env.mjs"; +import { resolveRuntimePorts, withRuntimePortEnv } from "../build/runtime-env.mjs"; import { createOmnirouteWsBridge } from "./v1-ws-bridge.mjs"; import { createResponsesWsProxy } from "./responses-ws-proxy.mjs"; import { randomUUID } from "node:crypto"; diff --git a/scripts/run-playwright-tests.mjs b/scripts/dev/run-playwright-tests.mjs similarity index 91% rename from scripts/run-playwright-tests.mjs rename to scripts/dev/run-playwright-tests.mjs index a4585354f6..3d775445d4 100644 --- a/scripts/run-playwright-tests.mjs +++ b/scripts/dev/run-playwright-tests.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node import { spawn } from "node:child_process"; -import { sanitizeColorEnv } from "./runtime-env.mjs"; +import { sanitizeColorEnv } from "../build/runtime-env.mjs"; const defaultArgs = ["test", "tests/e2e/*.spec.ts"]; const forwardedArgs = process.argv.slice(2); diff --git a/scripts/run-protocol-clients-tests.mjs b/scripts/dev/run-protocol-clients-tests.mjs similarity index 97% rename from scripts/run-protocol-clients-tests.mjs rename to scripts/dev/run-protocol-clients-tests.mjs index f0945eb924..83e4c13ded 100644 --- a/scripts/run-protocol-clients-tests.mjs +++ b/scripts/dev/run-protocol-clients-tests.mjs @@ -3,7 +3,7 @@ import { spawn } from "node:child_process"; import { join } from "node:path"; import { setTimeout as delay } from "node:timers/promises"; -import { sanitizeColorEnv } from "./runtime-env.mjs"; +import { sanitizeColorEnv } from "../build/runtime-env.mjs"; function parsePort(value, fallback) { const parsed = Number.parseInt(String(value), 10); diff --git a/scripts/run-standalone.mjs b/scripts/dev/run-standalone.mjs similarity index 76% rename from scripts/run-standalone.mjs rename to scripts/dev/run-standalone.mjs index 095f89b482..9a91b9aa92 100644 --- a/scripts/run-standalone.mjs +++ b/scripts/dev/run-standalone.mjs @@ -4,8 +4,8 @@ import { resolveRuntimePorts, withRuntimePortEnv, spawnWithForwardedSignals, -} from "./runtime-env.mjs"; -import { bootstrapEnv } from "./bootstrap-env.mjs"; +} from "../build/runtime-env.mjs"; +import { bootstrapEnv } from "../build/bootstrap-env.mjs"; const env = bootstrapEnv(); const runtimePorts = resolveRuntimePorts(env); diff --git a/scripts/smoke-electron-packaged.mjs b/scripts/dev/smoke-electron-packaged.mjs similarity index 99% rename from scripts/smoke-electron-packaged.mjs rename to scripts/dev/smoke-electron-packaged.mjs index f7baa136c7..473cbf6303 100644 --- a/scripts/smoke-electron-packaged.mjs +++ b/scripts/dev/smoke-electron-packaged.mjs @@ -9,7 +9,7 @@ import { fileURLToPath, pathToFileURL } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const ROOT = join(__dirname, ".."); +const ROOT = join(__dirname, "..", ".."); const DEFAULT_TIMEOUT_MS = 45_000; const DEFAULT_SETTLE_MS = 2_000; diff --git a/scripts/standalone-server-ws.mjs b/scripts/dev/standalone-server-ws.mjs similarity index 100% rename from scripts/standalone-server-ws.mjs rename to scripts/dev/standalone-server-ws.mjs diff --git a/scripts/sync-env.mjs b/scripts/dev/sync-env.mjs similarity index 100% rename from scripts/sync-env.mjs rename to scripts/dev/sync-env.mjs diff --git a/scripts/system-info.mjs b/scripts/dev/system-info.mjs similarity index 98% rename from scripts/system-info.mjs rename to scripts/dev/system-info.mjs index 6dbc2949c7..6d112a11e9 100644 --- a/scripts/system-info.mjs +++ b/scripts/dev/system-info.mjs @@ -3,7 +3,7 @@ * system-info.mjs — OmniRoute System Information Reporter (#280) * * Collects system/environment info for bug reports. - * Usage: node scripts/system-info.mjs [--output system-info.txt] + * Usage: node scripts/dev/system-info.mjs [--output system-info.txt] * * Output includes: * - Node.js version @@ -21,7 +21,7 @@ import { fileURLToPath } from "url"; import os from "os"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const ROOT = join(__dirname, ".."); +const ROOT = join(__dirname, "..", ".."); // ── Helpers ──────────────────────────────────────────────────────────────── diff --git a/scripts/v1-ws-bridge.mjs b/scripts/dev/v1-ws-bridge.mjs similarity index 100% rename from scripts/v1-ws-bridge.mjs rename to scripts/dev/v1-ws-bridge.mjs diff --git a/scripts/gen-provider-reference.ts b/scripts/docs/gen-provider-reference.ts similarity index 97% rename from scripts/gen-provider-reference.ts rename to scripts/docs/gen-provider-reference.ts index c8a62be86a..823d9f19d5 100644 --- a/scripts/gen-provider-reference.ts +++ b/scripts/docs/gen-provider-reference.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node // Generates docs/PROVIDER_REFERENCE.md from src/shared/constants/providers.ts. -// Run: node --import tsx/esm scripts/gen-provider-reference.ts +// Run: node --import tsx/esm scripts/docs/gen-provider-reference.ts import fs from "node:fs"; import path from "node:path"; @@ -22,10 +22,10 @@ import { VIDEO_PROVIDER_IDS, EMBEDDING_RERANK_PROVIDER_IDS, SELF_HOSTED_CHAT_PROVIDER_IDS, -} from "../src/shared/constants/providers.ts"; +} from "../../src/shared/constants/providers.ts"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT = path.resolve(__dirname, ".."); +const ROOT = path.resolve(__dirname, "..", ".."); const OUT_FILE = path.join(ROOT, "docs", "PROVIDER_REFERENCE.md"); type ProviderRecord = { diff --git a/scripts/generate-docs-index.mjs b/scripts/docs/generate-docs-index.mjs similarity index 94% rename from scripts/generate-docs-index.mjs rename to scripts/docs/generate-docs-index.mjs index 69c6babd88..85015cea42 100644 --- a/scripts/generate-docs-index.mjs +++ b/scripts/docs/generate-docs-index.mjs @@ -5,7 +5,7 @@ * src/app/docs/lib/docs-auto-generated.ts with static navigation + search data. * * This file is imported by both client and server components — NO fs/path imports. - * Run via: node scripts/generate-docs-index.mjs + * Run via: node scripts/docs/generate-docs-index.mjs * Automatically runs as prebuild step. */ @@ -15,7 +15,7 @@ import matter from "gray-matter"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT = path.resolve(__dirname, ".."); +const ROOT = path.resolve(__dirname, "..", ".."); const DOCS_DIR = path.join(ROOT, "docs"); const OUT_FILE = path.join(ROOT, "src", "app", "docs", "lib", "docs-auto-generated.ts"); @@ -127,8 +127,8 @@ if (!fs.existsSync(DOCS_DIR)) { fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true }); fs.writeFileSync( OUT_FILE, - `// AUTO-GENERATED by scripts/generate-docs-index.mjs — DO NOT EDIT MANUALLY -// Regenerate with: node scripts/generate-docs-index.mjs + `// AUTO-GENERATED by scripts/docs/generate-docs-index.mjs — DO NOT EDIT MANUALLY +// Regenerate with: node scripts/docs/generate-docs-index.mjs export interface AutoGenDocItem { slug: string; @@ -238,8 +238,8 @@ if (searchIndex.some((item) => item.slug === "api-reference")) { // ---------- Write output ---------- -const output = `// AUTO-GENERATED by scripts/generate-docs-index.mjs — DO NOT EDIT MANUALLY -// Regenerate with: node scripts/generate-docs-index.mjs +const output = `// AUTO-GENERATED by scripts/docs/generate-docs-index.mjs — DO NOT EDIT MANUALLY +// Regenerate with: node scripts/docs/generate-docs-index.mjs export interface AutoGenDocItem { slug: string; diff --git a/scripts/check_translations.py b/scripts/i18n/check_translations.py similarity index 97% rename from scripts/check_translations.py rename to scripts/i18n/check_translations.py index 80d662c0a7..2f2f38abe8 100755 --- a/scripts/check_translations.py +++ b/scripts/i18n/check_translations.py @@ -4,9 +4,9 @@ Translation check script for OmniRoute. Checks if all translation keys used in code exist in en.json. Usage: - python scripts/check_translations.py - python scripts/check_translations.py --verbose - python scripts/check_translations.py --fix + python scripts/i18n/check_translations.py + python scripts/i18n/check_translations.py --verbose + python scripts/i18n/check_translations.py --fix """ import json diff --git a/scripts/i18n_autotranslate.py b/scripts/i18n/i18n_autotranslate.py similarity index 97% rename from scripts/i18n_autotranslate.py rename to scripts/i18n/i18n_autotranslate.py index 9321ff57f6..17c1d169ef 100755 --- a/scripts/i18n_autotranslate.py +++ b/scripts/i18n/i18n_autotranslate.py @@ -6,7 +6,7 @@ API (like OmniRoute itself) to translate any English paragraphs into the target language. Usage: - python3 scripts/i18n_autotranslate.py --api-url http://localhost:20128/v1 --api-key sk-your-omniroute-key --model cx/gpt-5.4 + python3 scripts/i18n/i18n_autotranslate.py --api-url http://localhost:20128/v1 --api-key sk-your-omniroute-key --model cx/gpt-5.4 """ import os diff --git a/scripts/validate_translation.py b/scripts/i18n/validate_translation.py similarity index 99% rename from scripts/validate_translation.py rename to scripts/i18n/validate_translation.py index 087879fc00..5c1f236124 100755 --- a/scripts/validate_translation.py +++ b/scripts/i18n/validate_translation.py @@ -30,8 +30,10 @@ NC = "\033[0m" # Configuration - find repo root relative to this script _script_dir = Path(__file__).parent.resolve() -# If script is in scripts/ subfolder, go up one level to repo root -if _script_dir.name == "scripts": +# Walk up out of scripts//, scripts/, or stay at cwd +if _script_dir.name == "i18n" and _script_dir.parent.name == "scripts": + SCRIPT_DIR = _script_dir.parent.parent +elif _script_dir.name == "scripts": SCRIPT_DIR = _script_dir.parent else: SCRIPT_DIR = _script_dir diff --git a/src/app/api/system/env/repair/route.ts b/src/app/api/system/env/repair/route.ts index 64ed9c617e..1f8f8137ef 100644 --- a/src/app/api/system/env/repair/route.ts +++ b/src/app/api/system/env/repair/route.ts @@ -10,7 +10,7 @@ import { join } from "node:path"; import { NextResponse } from "next/server"; import { isAuthenticated } from "@/shared/utils/apiAuth"; // @ts-expect-error - .mjs without types -import { getEnvSyncPlan, syncEnv } from "../../../../../../scripts/sync-env.mjs"; +import { getEnvSyncPlan, syncEnv } from "../../../../../../scripts/dev/sync-env.mjs"; async function loadSyncHelpers() { return { getEnvSyncPlan, syncEnv }; diff --git a/src/app/api/system/version/route.ts b/src/app/api/system/version/route.ts index f05af793f1..94e4cda28b 100644 --- a/src/app/api/system/version/route.ts +++ b/src/app/api/system/version/route.ts @@ -234,7 +234,7 @@ export async function POST(req: NextRequest) { send({ step: "rebuild", status: "done", message: "Dependencies installed" }); try { - await execFileAsync("node", ["scripts/sync-env.mjs"], { + await execFileAsync("node", ["scripts/dev/sync-env.mjs"], { timeout: 15_000, cwd: process.cwd(), }); diff --git a/src/app/docs/lib/docs-auto-generated.ts b/src/app/docs/lib/docs-auto-generated.ts index c9a2f7988c..380e932c3b 100644 --- a/src/app/docs/lib/docs-auto-generated.ts +++ b/src/app/docs/lib/docs-auto-generated.ts @@ -1,5 +1,5 @@ -// AUTO-GENERATED by scripts/generate-docs-index.mjs — DO NOT EDIT MANUALLY -// Regenerate with: node scripts/generate-docs-index.mjs +// AUTO-GENERATED by scripts/docs/generate-docs-index.mjs — DO NOT EDIT MANUALLY +// Regenerate with: node scripts/docs/generate-docs-index.mjs export interface AutoGenDocItem { slug: string; diff --git a/src/lib/oauth/constants/oauth.ts b/src/lib/oauth/constants/oauth.ts index 2f0fd83440..7223690b09 100644 --- a/src/lib/oauth/constants/oauth.ts +++ b/src/lib/oauth/constants/oauth.ts @@ -16,7 +16,7 @@ import { buildGitLabOAuthEndpoints, GITLAB_DUO_DEFAULT_BASE_URL } from "../gitla * * All credentials are read exclusively from environment variables. * Default values match the public CLI client IDs from .env.example - * (auto-populated by scripts/sync-env.mjs on install). + * (auto-populated by scripts/dev/sync-env.mjs on install). * * These are public OAuth client credentials for desktop/CLI applications * that rely on PKCE for security (RFC 8252), not on secret confidentiality. diff --git a/src/lib/system/autoUpdate.ts b/src/lib/system/autoUpdate.ts index 1bf071fe45..bfa51c648b 100644 --- a/src/lib/system/autoUpdate.ts +++ b/src/lib/system/autoUpdate.ts @@ -235,7 +235,7 @@ export function buildSourceUpdateScript(latest: string, gitRemote = "origin"): s 'git branch "$backup_branch" 2>/dev/null || true', `git checkout "${targetTag}"`, "npm install --legacy-peer-deps", - "node scripts/sync-env.mjs 2>/dev/null || true", + "node scripts/dev/sync-env.mjs 2>/dev/null || true", "npm run build", "if command -v pm2 >/dev/null 2>&1; then", " pm2 restart omniroute --update-env || true", diff --git a/tests/fixtures/cursor/.gitignore b/tests/fixtures/cursor/.gitignore index ee0bf80a07..fd10f15f69 100644 --- a/tests/fixtures/cursor/.gitignore +++ b/tests/fixtures/cursor/.gitignore @@ -1,4 +1,4 @@ -# Captured cursor wire bytes from scripts/cursor-tap.cjs. +# Captured cursor wire bytes from scripts/ad-hoc/cursor-tap.cjs. # By default these are local-only — uncomment a specific fixture to # include it in the repo as a regression baseline. *.bin diff --git a/tests/integration/batch-e2e-rate-limit.test.ts b/tests/integration/batch-e2e-rate-limit.test.ts index a56e361d8a..adb58a130b 100644 --- a/tests/integration/batch-e2e-rate-limit.test.ts +++ b/tests/integration/batch-e2e-rate-limit.test.ts @@ -111,7 +111,7 @@ function createServerProcess() { const stderrLines: string[] = []; let exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null; - const child = spawn(process.execPath, ["scripts/run-next-playwright.mjs", "dev"], { + const child = spawn(process.execPath, ["scripts/dev/run-next-playwright.mjs", "dev"], { cwd: REPO_ROOT, env: { ...process.env, diff --git a/tests/integration/cursor-e2e.test.ts b/tests/integration/cursor-e2e.test.ts index 42175787bc..97fccb52fb 100644 --- a/tests/integration/cursor-e2e.test.ts +++ b/tests/integration/cursor-e2e.test.ts @@ -16,7 +16,7 @@ * node --import tsx/esm --test tests/integration/cursor-e2e.test.ts * * Capturing wire fixtures (separate workflow): - * CURSOR_TOKEN=... node scripts/cursor-tap.cjs single-turn-chat "say PING" + * CURSOR_TOKEN=... node scripts/ad-hoc/cursor-tap.cjs single-turn-chat "say PING" */ import test from "node:test"; diff --git a/tests/integration/resilience-http-e2e.test.ts b/tests/integration/resilience-http-e2e.test.ts index d1d42c7439..ae3b6fb983 100644 --- a/tests/integration/resilience-http-e2e.test.ts +++ b/tests/integration/resilience-http-e2e.test.ts @@ -184,7 +184,7 @@ function createServerProcess(dataDir: string, port: number) { const stdoutLines: string[] = []; const stderrLines: string[] = []; let exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null; - const child = spawn(process.execPath, ["scripts/run-next-playwright.mjs", "dev"], { + const child = spawn(process.execPath, ["scripts/dev/run-next-playwright.mjs", "dev"], { cwd: REPO_ROOT, env: { ...process.env, diff --git a/tests/unit/bootstrap-env.test.ts b/tests/unit/bootstrap-env.test.ts index 43e20bfd7c..d606db7ac2 100644 --- a/tests/unit/bootstrap-env.test.ts +++ b/tests/unit/bootstrap-env.test.ts @@ -5,7 +5,7 @@ import os from "node:os"; import path from "node:path"; import Database from "better-sqlite3"; -import { bootstrapEnv } from "../../scripts/bootstrap-env.mjs"; +import { bootstrapEnv } from "../../scripts/build/bootstrap-env.mjs"; function withTempEnv(fn) { const originalCwd = process.cwd(); diff --git a/tests/unit/build-next-isolated.test.ts b/tests/unit/build-next-isolated.test.ts index e5e8c93284..89e67156e7 100644 --- a/tests/unit/build-next-isolated.test.ts +++ b/tests/unit/build-next-isolated.test.ts @@ -11,7 +11,7 @@ const { pruneStandaloneArtifacts, resolveNextBuildEnv, syncStandaloneNativeAssets, -} = await import("../../scripts/build-next-isolated.mjs"); +} = await import("../../scripts/build/build-next-isolated.mjs"); async function withTempDir(fn) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "omniroute-build-next-isolated-")); diff --git a/tests/unit/electron-smoke-script.test.ts b/tests/unit/electron-smoke-script.test.ts index 183d621f31..f2fdcbe3d2 100644 --- a/tests/unit/electron-smoke-script.test.ts +++ b/tests/unit/electron-smoke-script.test.ts @@ -5,7 +5,7 @@ import { buildSmokeEnv, FATAL_LOG_PATTERNS, LINUX_EXECUTABLE_NAMES, -} from "../../scripts/smoke-electron-packaged.mjs"; +} from "../../scripts/dev/smoke-electron-packaged.mjs"; test("electron smoke discovers the default Linux executable name", () => { assert.ok(LINUX_EXECUTABLE_NAMES.includes("omniroute-desktop")); diff --git a/tests/unit/native-binary-compat.test.ts b/tests/unit/native-binary-compat.test.ts index 73d0a86bd7..120c5e7853 100644 --- a/tests/unit/native-binary-compat.test.ts +++ b/tests/unit/native-binary-compat.test.ts @@ -7,7 +7,7 @@ import { tmpdir } from "node:os"; import { detectNativeBinaryTarget, isNativeBinaryCompatible, -} from "../../scripts/native-binary-compat.mjs"; +} from "../../scripts/build/native-binary-compat.mjs"; function makeElfBinary(machine) { const buffer = Buffer.alloc(64); diff --git a/tests/unit/pack-artifact-policy.test.ts b/tests/unit/pack-artifact-policy.test.ts index 21f09440f1..0f6c42f992 100644 --- a/tests/unit/pack-artifact-policy.test.ts +++ b/tests/unit/pack-artifact-policy.test.ts @@ -10,12 +10,12 @@ import { findMissingArtifactPaths, findUnexpectedArtifactPaths, normalizeArtifactPath, -} from "../../scripts/pack-artifact-policy.ts"; +} from "../../scripts/build/pack-artifact-policy.ts"; test("normalizeArtifactPath normalizes slashes and leading relative markers", () => { assert.equal( - normalizeArtifactPath("./app\\scripts\\scratch\\test.js"), - "app/scripts/scratch/test.js" + normalizeArtifactPath("./app\\scripts\\ad-hoc\\test.js"), + "app/scripts/ad-hoc/test.js" ); }); @@ -25,7 +25,7 @@ test("findUnexpectedArtifactPaths flags staged app files outside the allowlist", "open-sse/services/compression/engines/rtk/filters/generic-output.json", "open-sse/services/compression/rules/en/filler.json", "package-lock.json", - "scripts/sync-env.mjs", + "scripts/dev/sync-env.mjs", "server.js", ], { @@ -43,8 +43,8 @@ test("findUnexpectedArtifactPaths flags app pack files outside the allowlist", ( "app/open-sse/services/compression/engines/rtk/filters/generic-output.json", "app/open-sse/services/compression/rules/en/filler.json", "app/server.js", - "app/scripts/sync-env.mjs", - "app/scripts/prepublish.mjs", + "app/scripts/dev/sync-env.mjs", + "app/scripts/build/prepublish.mjs", "docs/extra.md", ], { @@ -53,7 +53,7 @@ test("findUnexpectedArtifactPaths flags app pack files outside the allowlist", ( } ); - assert.deepEqual(unexpectedPaths, ["app/scripts/prepublish.mjs", "docs/extra.md"]); + assert.deepEqual(unexpectedPaths, ["app/scripts/build/prepublish.mjs", "docs/extra.md"]); }); test("findMissingArtifactPaths flags missing root runtime files in the tarball", () => { @@ -62,8 +62,8 @@ test("findMissingArtifactPaths flags missing root runtime files in the tarball", "app/server.js", "bin/omniroute.mjs", "package.json", - "scripts/postinstall.mjs", - "scripts/postinstallSupport.mjs", + "scripts/build/postinstall.mjs", + "scripts/build/postinstallSupport.mjs", ], PACK_ARTIFACT_REQUIRED_PATHS ); @@ -77,7 +77,7 @@ test("findMissingArtifactPaths flags missing root runtime files in the tarball", "bin/cli/index.mjs", "bin/mcp-server.mjs", "bin/nodeRuntimeSupport.mjs", - "scripts/native-binary-compat.mjs", + "scripts/build/native-binary-compat.mjs", "src/shared/utils/nodeRuntimeSupport.ts", ]); }); diff --git a/tests/unit/postinstall-support.test.ts b/tests/unit/postinstall-support.test.ts index 65b972ef92..55472d8aae 100644 --- a/tests/unit/postinstall-support.test.ts +++ b/tests/unit/postinstall-support.test.ts @@ -4,7 +4,7 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; -import { hasStandaloneAppBundle } from "../../scripts/postinstallSupport.mjs"; +import { hasStandaloneAppBundle } from "../../scripts/build/postinstallSupport.mjs"; test("hasStandaloneAppBundle returns false for source checkout without standalone app", () => { const root = mkdtempSync(join(tmpdir(), "omniroute-postinstall-src-")); diff --git a/tests/unit/responses-ws-proxy.test.mjs b/tests/unit/responses-ws-proxy.test.mjs index b2c02ce845..382ced9b9c 100644 --- a/tests/unit/responses-ws-proxy.test.mjs +++ b/tests/unit/responses-ws-proxy.test.mjs @@ -2,7 +2,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import http from "node:http"; -const { createResponsesWsProxy } = await import("../../scripts/responses-ws-proxy.mjs"); +const { createResponsesWsProxy } = await import("../../scripts/dev/responses-ws-proxy.mjs"); function listen(server) { return new Promise((resolve) => { diff --git a/tests/unit/run-next-playwright.test.ts b/tests/unit/run-next-playwright.test.ts index 4bd2665915..9b66bca43d 100644 --- a/tests/unit/run-next-playwright.test.ts +++ b/tests/unit/run-next-playwright.test.ts @@ -4,7 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const playwrightRunner = await import("../../scripts/run-next-playwright.mjs"); +const playwrightRunner = await import("../../scripts/dev/run-next-playwright.mjs"); test("resolvePlaywrightAppBackupDir uses a per-run backup when a stale backup already exists", () => { const cwd = "/tmp/omniroute-playwright-runner"; diff --git a/tests/unit/runtime-env.test.ts b/tests/unit/runtime-env.test.ts index 216831349e..6c98fdfd2c 100644 --- a/tests/unit/runtime-env.test.ts +++ b/tests/unit/runtime-env.test.ts @@ -7,7 +7,7 @@ import { pathToFileURL } from "node:url"; const require = createRequire(import.meta.url); const childProcess = require("node:child_process"); -const modulePath = path.join(process.cwd(), "scripts/runtime-env.mjs"); +const modulePath = path.join(process.cwd(), "scripts/build/runtime-env.mjs"); const originalSpawn = childProcess.spawn; const originalProcessOn = process.on; diff --git a/tests/unit/runtime-ports.test.ts b/tests/unit/runtime-ports.test.ts index fedea0a3b5..8804330658 100644 --- a/tests/unit/runtime-ports.test.ts +++ b/tests/unit/runtime-ports.test.ts @@ -3,7 +3,7 @@ import assert from "node:assert/strict"; // We test the standalone (scripts/) version of port resolution since // the src/ version uses @/ alias that requires the full Next.js build. -import { parsePort, resolveRuntimePorts } from "../../scripts/runtime-env.mjs"; +import { parsePort, resolveRuntimePorts } from "../../scripts/build/runtime-env.mjs"; describe("parsePort", () => { it("parses a valid port number", () => { diff --git a/tests/unit/sync-env.test.ts b/tests/unit/sync-env.test.ts index c47cd0ad7b..d5bedcbd7d 100644 --- a/tests/unit/sync-env.test.ts +++ b/tests/unit/sync-env.test.ts @@ -4,7 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -const { syncEnv } = (await import("../../scripts/sync-env.mjs")) as { +const { syncEnv } = (await import("../../scripts/dev/sync-env.mjs")) as { syncEnv: (opts?: { rootDir?: string; quiet?: boolean; scope?: string }) => { created: boolean; added: number; diff --git a/tests/unit/v1-ws-bridge.test.ts b/tests/unit/v1-ws-bridge.test.ts index 859ad6b805..4ccbbd78a8 100644 --- a/tests/unit/v1-ws-bridge.test.ts +++ b/tests/unit/v1-ws-bridge.test.ts @@ -2,7 +2,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import http from "node:http"; -const { createOmnirouteWsBridge } = await import("../../scripts/v1-ws-bridge.mjs"); +const { createOmnirouteWsBridge } = await import("../../scripts/dev/v1-ws-bridge.mjs"); function listen(server) { return new Promise((resolve) => {