mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-14 11:12:17 +03:00
* fix(ci): clear base-reds on release/v3.8.50 (round 4) Drains the HARD failures reported by Release-Green run 31693210948 on issue #9985 (ESLint errors: 2) plus the merge-integrity red every open PR is inheriting. - ESLint error 1: @omniroute/opencode-plugin/src/index.ts had a stray extra '});' (introduced by #9316) that broke parsing with 'unexpected file in NFT list' on the build path. - ESLint error 2: cli-env-inline-comment-10100.test.ts used new Function to extract parseEnvValue from the bin entrypoint (no-new-func, Hard Rule #3). Extracted the helper to bin/cli/utils/parseEnvValue.mjs and import it from both the entrypoint and the test (same behavior, no eval). - open-sse-typecheck (Fast Quality Gates): open-sse/utils/stream.ts imported sseCommentsEnabled twice (#9378) causing TS2300 Duplicate identifier; removed the duplicate import. - Merge integrity (changelog + generated skills): skills/omni-settings/SKILL.md was edited manually by #10169 without updating the generator source, so check:agent-skills-sync failed on every PR (Generated: 1). Moved the curated thinking-budget content into a <!-- skill:custom-start --> block (the documented preservation mechanism), which the generator now keeps in sync. Refs #9985 * fix(tests): align wave1-a poolside test with #10216 probed catalog #10216 published Poolside's two authenticated-probe models (poolside/laguna-xs-2.1, poolside/laguna-s-2.1) as static seeds, but the wave1-a free-tier test still asserted 'no invented static model ids' (entry.models === []), failing every open PR. Separate poolside from the empty-models assertion and pin its probed catalog explicitly so a future catalog change is a deliberate update, not a silent drift. * fix(pack): register parseEnvValue.mjs in PACK_ARTIFACT_REQUIRED_PATHS The extract of parseEnvValue to bin/cli/utils/parseEnvValue.mjs added a new direct import to bin/omniroute.mjs, which pack-artifact-entrypoint-closures enforces against PACK_ARTIFACT_REQUIRED_PATHS. Register the module so a future tarball omission fails loudly. * fix(combo): restore default same-model retry semantics after #10217 #10217 wired config.failoverBeforeRetry into the same-model retry guard in both the priority/auto and round-robin loops, but DEFAULT_COMBO_CONFIG defaulted the flag to true — flipping same-model retry off for every combo that never touched the setting, not just the opt-in case. Round-4 bisect (06f41cda63vsd2fd88dfbc) reproduced this against tests/unit/combo-499-abort.test.ts, tests/unit/combo-quota-exhaustion-only-fallback.test.ts and tests/unit/combo-stream-readiness-fallback.test.ts. Flip the default to false so the historical retry-before-failover behavior returns for combos that never set the flag, while explicit opt-in (the two new tests #10217 added to combo-routing-engine.test.ts) still works. * fix(quality): register visionBridge-responses-9597 in stryker tap.testFiles check-mutation-test-coverage.mjs flagged tests/unit/guardrails/visionBridge-responses-9597.test.ts as covering open-sse/services/combo/comboStructure.ts without being listed in stryker.conf.json's tap.testFiles array. Add it so mutation coverage attribution stays accurate. * test(pack): expect parseEnvValue.mjs in the missing-artifact-paths fixture The prior commit on this branch registered bin/cli/utils/parseEnvValue.mjs in PACK_ARTIFACT_REQUIRED_PATHS but the "findMissingArtifactPaths flags missing root runtime files in the tarball" test still hardcoded the old expected list, so it never accounted for the new required path being absent from the simulated tarball. Add it in its alphabetical slot. * chore(lint): prune stale no-explicit-any suppression for call-log-file-rotation --prune-suppressions found tests/unit/call-log-file-rotation.test.ts no longer produces the 5 suppressed @typescript-eslint/no-explicit-any warnings recorded in config/quality/eslint-suppressions.json. Remove the dead entry so a regression would be caught again. Full-tree run with --max-warnings 0 is clean: 0 errors, 0 warnings. * fix(combo): decouple failoverBeforeRetry same-model guard from the skipUpstreamRetry default Audit found that DEFAULT_COMBO_CONFIG.failoverBeforeRetry has defaulted to true since before #10217 (predates #2417), and that value also feeds the independent skipUpstreamRetry mechanism (src/sse/handlers/chat.ts:859,1126). The previous commit on this branch flipped that default to false to fix the #10217 same-model retry guard, which silently disabled skipUpstreamRetry's own default-on behavior for every combo without an opt-in — a regression in the opposite direction (executor-level retries before the loop's own failover, changing latency/failure behavior). Revert the default back to true and decouple the two mechanisms instead: resolveComboConfig/resolveComboSetupConfig now also compute failoverBeforeRetryExplicit, true only when a cascade layer (combo/provider/ global) literally sets failoverBeforeRetry to true — not merely inherited from the default. The #10217 same-model retry guards in combo.ts (priority/ auto and round-robin loops) now read failoverBeforeRetryExplicit instead of config.failoverBeforeRetry, restoring opt-in-only behavior for that guard while the skipUpstreamRetry pass-through (config.failoverBeforeRetry at combo.ts:1297,2865) is untouched and keeps its historical default-on. * fix(combo,i18n): align getDefaultComboConfig with 10217 explicit flag; pt denoRelay entities Two round-4 follow-ups exposed by the combinated base-red PR run: 1. comboConfig.ts: #10217 round-4 fix (104afeda4e) added failoverBeforeRetryExplicit to resolveComboConfig/resolveComboSetupConfig but getDefaultComboConfig() returned only DEFAULT_COMBO_CONFIG, so the combo-config.test.ts deepEqual (resolveComboConfig(null) === getDefaultComboConfig()) failed on the extra field. Mirror the opt-in flag as false in the default. 2. pt.json: denoRelayOrgDomainHint still carried raw <app-name>/<org-slug> (the UNCLOSED_TAG RSC regression) — encode as <...> like the other 42 locales, greening i18n-deno-relay-unclosed-tag.test.ts. * chore(lint): disable @next/next/no-location-assign-relative-destination pending per-case review (#10292) The eslint-config-next bump in #10043 shipped this new rule, flagging 6 pre-existing window.location.href navigations — several are deliberate full-page reloads (login/logout state reset). Off with tracking issue rather than a blanket router.push rewrite. * fix(i18n): fill 439 missing UI keys (thinkingMode ×39 locales + pt catch-up) to restore 100% coverage The #10169 Thinking Budget keys existed only in en/pt-BR/vi and the pt (PT-PT) catalog from #10250 lagged 88 recent keys, dropping i18nUiCoverage to 99.3% vs the frozen 100% ratchet baseline. Translated via the i18n:sync-ui marker pipeline; glossary + ICU placeholder post-pass clean. * fix(i18n): zh-TW glossary — replace retired 默認 with canonical 預設 in new thinkingMode keys * chore(quality): rebase dead-code baseline 248 -> 409 for knip 6.32 bump (#10043) dependabot #10043 upgraded knip 6.27 -> 6.32, which detects 162 MORE genuinely-unused exports (331 vs 169) that 6.27 missed; DEAD_FILES unchanged (78). Reproduced identically on the clean release/v3.8.50 tip266e39d3with a fresh 6.32 node_modules, so every PR is born red until the tool change is absorbed. Owner authorized rebaseline (2026-08-13 via PR #10260). Structural cleanup of the newly-surfaced dead exports remains separate debt. --------- Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com> Co-authored-by: backryun <bakryun0718@proton.me>
202 lines
7.5 KiB
JavaScript
202 lines
7.5 KiB
JavaScript
import nextVitals from "eslint-config-next/core-web-vitals";
|
||
import tseslint from "typescript-eslint";
|
||
|
||
// #7879: bar NEW local `toNumber` definitions outside the canonical helper.
|
||
// Pre-existing definitions (~51 across the codebase) are frozen via
|
||
// config/quality/eslint-suppressions.json and migrated tier-by-tier; only a
|
||
// genuinely NEW `function toNumber`/`const toNumber = ...` should fail.
|
||
const TO_NUMBER_RESTRICTION = {
|
||
selector: "FunctionDeclaration[id.name='toNumber'], VariableDeclarator[id.name='toNumber']",
|
||
message:
|
||
"New local `toNumber` definitions are barred — import `toNumber` from " +
|
||
"`@/shared/utils/numeric` instead (#7879). See that module's JSDoc for the " +
|
||
"canonical coercion shape and the `toNumberOrNull`/`toNumberArray` variants.",
|
||
};
|
||
|
||
const LOCAL_DB_IMPORT_RESTRICTION = {
|
||
regex: "^(?:@/lib/localDb(?:\\.ts)?|(?:\\.\\.?/)+(?:lib/)?localDb(?:\\.ts)?)$",
|
||
message:
|
||
"The localDb compatibility barrel is restricted — import the owning domain module " +
|
||
"from `@/lib/db/` instead.",
|
||
};
|
||
|
||
const EXECUTOR_IMPORT_RESTRICTION = {
|
||
regex: "^(?:@omniroute/)?open-sse/executors(?:/|$)",
|
||
message: "Executor implementations must stay behind an open-sse handler or service boundary.",
|
||
};
|
||
|
||
const PROP_TYPES_RESTRICTION = {
|
||
name: "prop-types",
|
||
message: "PropTypes are deprecated. Use TypeScript types/interfaces instead.",
|
||
};
|
||
|
||
const IMPORT_BOUNDARY_RESTRICTIONS = {
|
||
paths: [PROP_TYPES_RESTRICTION],
|
||
patterns: [LOCAL_DB_IMPORT_RESTRICTION],
|
||
};
|
||
|
||
/** @type {import("eslint").Linter.Config[]} */
|
||
const eslintConfig = [
|
||
...nextVitals,
|
||
// Pacote 4 (plano mestre testes+CI, 2026-07-04) — zero-warning policy: TODA regra roda
|
||
// como "error" e a dívida pré-existente vive congelada por arquivo+regra em
|
||
// config/quality/eslint-suppressions.json (ESLint bulk suppressions nativo). Violação
|
||
// NOVA = vermelho no ato (lint-staged no pre-commit + job lint-guard no fast path);
|
||
// o drift de +41/+88 warnings/ciclo que era rebaselinado às cegas na release morre no
|
||
// PR que o introduz. Aperto do baseline: npx eslint . --prune-suppressions
|
||
// --suppressions-location config/quality/eslint-suppressions.json (na release).
|
||
{
|
||
// Escopo = onde os presets do next registram estes plugins (bloco global sem `files`
|
||
// atingiria scripts/*.mjs sem o plugin react-hooks e explodiria o flat config).
|
||
files: ["src/**/*.{ts,tsx,js,jsx}"],
|
||
rules: {
|
||
"react-hooks/exhaustive-deps": "error",
|
||
"@next/next/no-img-element": "error",
|
||
"import/no-anonymous-default-export": "error",
|
||
},
|
||
},
|
||
// FASE-02: Security rules (strict everywhere)
|
||
{
|
||
rules: {
|
||
"no-eval": "error",
|
||
"no-implied-eval": "error",
|
||
"no-new-func": "error",
|
||
"no-restricted-imports": ["error", IMPORT_BOUNDARY_RESTRICTIONS],
|
||
// New rule shipped by the eslint-config-next bump (#10043); flags 6 pre-existing
|
||
// window.location.href navigations, several of which are deliberate full-page
|
||
// reloads (login/logout state reset). Off pending per-case review — issue #10292.
|
||
"@next/next/no-location-assign-relative-destination": "off",
|
||
},
|
||
},
|
||
// G14: DB internals may use the compatibility barrel while it is decomposed; all
|
||
// other source files must import the owning src/lib/db domain module directly.
|
||
{
|
||
files: ["src/lib/db/**/*.{ts,tsx,js,jsx}"],
|
||
rules: {
|
||
"no-restricted-imports": [
|
||
"error",
|
||
{
|
||
paths: [PROP_TYPES_RESTRICTION],
|
||
},
|
||
],
|
||
},
|
||
},
|
||
// G14: App routes/components must delegate provider execution through handlers or
|
||
// services instead of reaching into executor implementations.
|
||
{
|
||
files: ["src/app/**/*.{ts,tsx,js,jsx}"],
|
||
rules: {
|
||
"no-restricted-imports": [
|
||
"error",
|
||
{
|
||
...IMPORT_BOUNDARY_RESTRICTIONS,
|
||
patterns: [LOCAL_DB_IMPORT_RESTRICTION, EXECUTOR_IMPORT_RESTRICTION],
|
||
},
|
||
],
|
||
},
|
||
},
|
||
// i18n: ham toLowerCase().includes() arama pattern'ini engelle
|
||
// (Türkçe İ/ı karakterlerini bozar — matchesSearch kullanılmalı).
|
||
// "warn" (error değil): kuralın eklendiği anda kod tabanında zaten bu pattern'i
|
||
// kullanan ~19 satır var; aşamalı temizlik için uyarı seviyesinde tutuluyor
|
||
// (proje politikası: 0 error, warning'ler tolere edilir).
|
||
{
|
||
files: ["src/app/**/*.{ts,tsx}", "src/components/**/*.{ts,tsx}"],
|
||
rules: {
|
||
"no-restricted-syntax": [
|
||
"error",
|
||
{
|
||
selector:
|
||
"CallExpression[callee.property.name='includes'][callee.object.callee.property.name='toLowerCase']",
|
||
message:
|
||
"Türkçe-güvenli arama için matchesSearch() kullan (@/shared/utils/turkishText). Ham toLowerCase().includes() İ/ı karakterlerini bozar.",
|
||
},
|
||
TO_NUMBER_RESTRICTION,
|
||
],
|
||
},
|
||
},
|
||
// #7879: same toNumber restriction for the rest of src/ and open-sse/ — kept
|
||
// as a separate block (via `ignores`) so it does not clobber the
|
||
// app/components-scoped rule array above (flat config replaces a rule's
|
||
// options entirely per matching file, it does not merge arrays).
|
||
{
|
||
files: ["src/**/*.ts", "open-sse/**/*.ts"],
|
||
ignores: ["src/app/**", "src/components/**"],
|
||
rules: {
|
||
"no-restricted-syntax": ["error", TO_NUMBER_RESTRICTION],
|
||
},
|
||
},
|
||
// Canonical helper module itself is exempt from its own restriction.
|
||
{
|
||
files: ["src/shared/utils/numeric.ts"],
|
||
rules: {
|
||
"no-restricted-syntax": "off",
|
||
},
|
||
},
|
||
// Relaxed rules for open-sse and tests (incremental adoption)
|
||
{
|
||
files: ["open-sse/**/*.ts", "tests/**/*.mjs", "tests/**/*.ts"],
|
||
plugins: {
|
||
"@typescript-eslint": tseslint.plugin,
|
||
},
|
||
rules: {
|
||
"@typescript-eslint/no-explicit-any": "error",
|
||
"@next/next/no-assign-module-variable": "off",
|
||
"react-hooks/rules-of-hooks": "off",
|
||
},
|
||
},
|
||
// Global ignores — keep ESLint scoped to source files only
|
||
{
|
||
ignores: [
|
||
// Next.js build output (distDir now .build/next; keep .next for legacy)
|
||
".next/**",
|
||
".build/**",
|
||
"src/.next/**",
|
||
"out/**",
|
||
"build/**",
|
||
"dist/**",
|
||
"coverage/**",
|
||
"next-env.d.ts",
|
||
// Scripts and binaries
|
||
"scripts/**",
|
||
"bin/**",
|
||
// Dependencies
|
||
"node_modules/**",
|
||
".worktrees/**",
|
||
// Nested git worktrees created by review/resolve skills live under
|
||
// .claude/ (gitignored). They hold other sessions' in-progress work and
|
||
// their files move mid-scan, so never lint them from the main checkout.
|
||
".claude/**",
|
||
".omnivscodeagent/**",
|
||
// _tasks/ — planning/handoff/research artifacts (gitignored, external code)
|
||
"_tasks/**",
|
||
// .agents/ — skill definitions + their helper scripts (gitignored; the
|
||
// canonical copy lives here and is symlinked into .claude/).
|
||
".agents/**",
|
||
// .source/ — fumadocs codegen output (@ts-nocheck + bundler-only import
|
||
// query params like `?collection=docs`, which are not valid TS on their own).
|
||
".source/**",
|
||
// VS Code extension and its large test fixtures
|
||
"vscode-extension/**",
|
||
"_references/**",
|
||
"_mono_repo/**",
|
||
// Electron app
|
||
"electron/**",
|
||
// Docs
|
||
"docs/**",
|
||
// Open-SSE compiled/bundled output
|
||
"open-sse/mcp-server/dist/**",
|
||
// Playwright test output
|
||
"playwright-report/**",
|
||
"test-results/**",
|
||
// Legacy app/ and QA backup dirs (renamed to dist/ in Layer 1)
|
||
"app/**",
|
||
"app.__qa_backup/**",
|
||
// CLI package copy directory
|
||
"clipr/**",
|
||
],
|
||
},
|
||
];
|
||
|
||
export default eslintConfig;
|