Files
OmniRoute/config
Diego Rodrigues de Sa e Souza ef2a89bd69 chore(lint): batch 1 of #12146 — dashboard/cli-code react-hooks violations resolved (#12160)
* chore(lint): batch 1 of #12146 — resolve the react-hooks compiler violations in dashboard/cli-code

Real refactors, no suppressions — the 42 frozen react-hooks/* entries for the
12 dashboard/cli-code files (plus Antigravity's exhaustive-deps one) are
removed from config/quality/eslint-suppressions.json and the files now lint
clean under the React Compiler rules.

Techniques, per pattern:

- set-state-in-effect ("default API key" effects — Antigravity, Claude, Cline,
  Codex, Droid, GrokBuild, Kilo, OpenClaw): the setState-in-effect that copied
  apiKeys[0].id into the selection state is deleted; an `effective*` value is
  derived during render (`selected || apiKeys[0]?.id`) and used by the select
  and the submit handlers. Behavior identical, one less render pass.

- immutability ("accessed before declared") + set-state-in-effect on the
  expand-time loaders (all tool cards): the fetchers (checkXStatus,
  fetchModelAliases, fetchBackups, fetchProfiles, loadSavedMappings) are
  hoisted above the effect as useCallback with correct deps, listed in the
  effect deps, and invoked through an async continuation
  (`void (async () => { await Promise.all([...]) })()`) so no setState runs
  synchronously in the effect body.

- set-state-in-effect ("init form from fetched status" effects — Claude,
  Cline, Codex, Droid, OpenClaw): the status-parsing effects are deleted and
  their logic now runs inside checkXStatus right after the fetch resolves
  (setState after await), keeping the same one-time ref guards. Codex's config
  parser became syncFormFromStatus(), called on both success and error paths.

- HermesAgentToolCard: Date.now() in render (purity) is snapshotted once via a
  lazy useState initializer; the batchStatus seeding effect is replaced by a
  derived `displayRoles` (useMemo over batchStatus with currentRoles taking
  precedence); the collapse-reset effect moved into the header toggle handler.

- ClaudeClassifierCompatToggle / CliProfileAutoSyncToggles / Cliproxyapi /
  GrokBuild: mount/expand loads wrapped in the same async continuation.

- DroidToolCard's isOmniRouteEntry helper hoisted to module scope (pure).

Validation: eslint with suppressions --max-warnings 0 on the 12 files (clean),
scripts/check/check-dashboard-typecheck.mjs (OK, within frozen baseline),
vitest UI suites for the touched cards (15 files / 57 tests green, plus the 3
quarantined #8618 files run explicitly: 27 tests green), and the node-native
cli-code tests (61 tests green).

Refs #12146

* chore(lint): batch 1 follow-up — hoist the settings-init helpers so the cognitive gate stays flat

The first pass folded the one-time form init into the status fetchers, which pushed
sonarjs/cognitive-complexity to 1 in Claude/Cline/OpenClaw tool cards (caught by the
new-code gate on the PR). The init logic now lives in module-level helpers
(initXFormFromSettings + defaultKeyId); complexityNewCode=-1, cognitiveComplexityNewCode=0.
2026-08-31 01:06:43 -03:00
..
2026-07-13 09:12:40 -03:00