Skip to content

refactor(dashboard): extract auth-import modals — #3501 Phase 1a - #3634

Merged
diegosouzapw merged 1 commit into
release/v3.8.22from
fix/3501-phase1-modals
Jun 11, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.22from
fix/3501-phase1-modals

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

#3501 Phase 1a — Extract the three auth-import modal clusters

Builds on Phase 0 (#3633). Extracts the three self-contained auth-import modal clusters out of ProviderDetailPageClient.tsx into providers/[id]/components/modals/:

New file Exports LOC
ImportCodexAuthModal.tsx ImportCodexAuthModal + ApplyCodexAuthModal 744
ImportClaudeAuthModal.tsx ImportClaudeAuthModal + ApplyClaudeAuthModal 731
ImportGeminiAuthModal.tsx ImportGeminiAuthModal + ApplyGeminiAuthModal 707

ProviderDetailPageClient.tsx: 12,882 → 10,720 LOC.

Why these first

The plan (#3501) calls these out as "trivially extractable first" — each cluster has a clean { onClose, onSuccess } / inline-prop interface and ships with its own co-located helpers (JWT parse, bulk-paste, JSON preview), so the move is structural only, no behavior change.

Validation

  • ✅ typecheck:core: clean (0 errors) — the compiler is the oracle that every reference resolves
  • ✅ lint: 0 errors; ✅ prettier: clean
  • ✅ Phase 0 page smoke test still green (mount/import graph unaffected)
  • ✅ new standalone render test: each extracted modal mounts on its own (Hard Rule fix(oauth): prevent connection test from corrupting valid tokens #8)
  • ✅ file-size: each new file < 800 cap (unused imports pruned); client ratchet lowered to 10,720

Part of #3501. Co-authored with @oyi77 (parallel effort in #3627).

Strangler-fig decomposition of providers/[id], building on Phase 0. Extracts
the three self-contained auth-import modal clusters into components/modals/:

- ImportCodexAuthModal + ApplyCodexAuthModal (+ co-located helpers)
- ImportClaudeAuthModal + ApplyClaudeAuthModal
- ImportGeminiAuthModal + ApplyGeminiAuthModal

ProviderDetailPageClient.tsx: 12,882 -> 10,720 LOC. Each modal cluster had a
clean { onClose, onSuccess } / inline-prop interface and its own helpers, so the
move is structural only. Unused imports pruned (each new file < 800-LOC cap).

Validation: typecheck:core clean, lint 0 errors, prettier clean, the Phase 0
page smoke test still green (mount unaffected), and a new standalone render test
proves each extracted modal mounts on its own (Hard Rule #8). file-size ratchet
lowered for the client.

Part of #3501. Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
@diegosouzapw
diegosouzapw merged commit fd1e08b into release/v3.8.22 Jun 11, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request extracts the Codex, Claude, and Gemini auth-import modal clusters from the large ProviderDetailPageClient.tsx component into standalone files, updating the file size baseline and adding a regression test. The review feedback highlights critical runtime errors caused by using the Node.js global Buffer in client-side components, state leakage issues where parsed JSON states are not reset to null upon parsing failures, and a missing email preview in the Gemini success notification when pasting credentials. Additionally, the reviewer noted a style guide violation regarding the placement of the test file, which must be moved to the tests/ directory.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +21 to +30
function extractEmailFromJwtLocal(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of Node.js global Buffer in a client-side component ("use client") will cause a ReferenceError: Buffer is not defined at runtime in the browser. Use the standard browser atob function to decode the JWT payload instead.

Suggested change
function extractEmailFromJwtLocal(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}
function extractEmailFromJwtLocal(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
const payload = JSON.parse(atob(base64));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}

Comment on lines +21 to +30
function extractEmailFromGeminiJwt(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of Node.js global Buffer in a client-side component ("use client") will cause a ReferenceError: Buffer is not defined at runtime in the browser. Use the standard browser atob function to decode the JWT payload instead.

Suggested change
function extractEmailFromGeminiJwt(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}
function extractEmailFromGeminiJwt(idToken: string): string | null {
try {
const parts = idToken.split(".");
if (parts.length !== 3) return null;
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
const payload = JSON.parse(atob(base64));
return typeof payload.email === "string" ? payload.email : null;
} catch {
return null;
}
}

Comment on lines +81 to +98
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
notify.error(
typeof t.has === "function" && t.has("claudeImportInvalidJson")
? t("claudeImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If parsing the uploaded file fails, singleJson is not reset to null. If a user previously uploaded a valid file, the state will leak and the button will remain enabled, submitting the old valid file instead of the new invalid one. Reset singleJson to null in the catch block.

Suggested change
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
notify.error(
typeof t.has === "function" && t.has("claudeImportInvalidJson")
? t("claudeImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
setSingleJson(null);
notify.error(
typeof t.has === "function" && t.has("claudeImportInvalidJson")
? t("claudeImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};

Comment on lines +75 to +92
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
notify.error(
typeof t.has === "function" && t.has("geminiImportInvalidJson")
? t("geminiImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If parsing the uploaded file fails, singleJson is not reset to null. If a user previously uploaded a valid file, the state will leak and the button will remain enabled, submitting the old valid file instead of the new invalid one. Reset singleJson to null in the catch block.

Suggested change
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
notify.error(
typeof t.has === "function" && t.has("geminiImportInvalidJson")
? t("geminiImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};
const handleSingleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const json = JSON.parse(ev.target?.result as string);
setSingleJson(json);
} catch {
setSingleJson(null);
notify.error(
typeof t.has === "function" && t.has("geminiImportInvalidJson")
? t("geminiImportInvalidJson")
: "Could not parse the file as JSON"
);
}
};
reader.readAsText(file);
};

Comment on lines +132 to +144
function handleSingleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
handleSinglePreview(JSON.parse(ev.target?.result as string));
} catch {
setSingleParseError(t("codexImportInvalidJson") || "Could not parse JSON");
}
};
reader.readAsText(file);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If parsing the uploaded file fails, singleParsedJson is not reset to null. Reset singleParsedJson to null in the catch block to prevent state leakage from a previously valid upload.

Suggested change
function handleSingleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
handleSinglePreview(JSON.parse(ev.target?.result as string));
} catch {
setSingleParseError(t("codexImportInvalidJson") || "Could not parse JSON");
}
};
reader.readAsText(file);
}
function handleSingleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
handleSinglePreview(JSON.parse(ev.target?.result as string));
} catch {
setSingleParsedJson(null);
setSingleParseError(t("codexImportInvalidJson") || "Could not parse JSON");
}
};
reader.readAsText(file);
}

return;
}

const preview = previewGeminiJson(singleJson);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When importing via the "Paste" tab, singleJson is null, which means previewGeminiJson(singleJson) will return null for the email, and the success notification will not display the imported account email. Parse the pasted text to extract the email for the success notification.

Suggested change
const preview = previewGeminiJson(singleJson);
let jsonToPreview = singleJson;
if (singleSubTab === "paste") {
try {
jsonToPreview = JSON.parse(singlePasteText);
} catch {}
}
const preview = previewGeminiJson(jsonToPreview);

Comment on lines +1 to +6
// @vitest-environment jsdom
//
// Phase 1a regression test for Issue #3501. The three auth-import modal clusters
// (Codex/Claude/Gemini) were extracted out of the 12.8K-LOC god-component into
// standalone files. This proves each now mounts in isolation with its clean
// { onClose, onSuccess } interface — the payoff of the extraction (Hard Rule #8).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the Repository Style Guide (Section 1: File Placement & Organization), all unit tests, integration tests, ecosystem tests, or Vitest files MUST strictly be placed within the tests/ directory (e.g., tests/unit/, tests/integration/). Please move this test file to the tests/ directory.

References
  1. 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 (/). (link)

diegosouzapw added a commit that referenced this pull request Jun 11, 2026
#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
@diegosouzapw
diegosouzapw deleted the fix/3501-phase1-modals branch June 11, 2026 15:33
diegosouzapw added a commit that referenced this pull request Jun 11, 2026
* chore(release): open v3.8.22 development cycle

* refactor(dashboard): extract ProviderDetailPageClient — #3501 Phase 0 (#3633)

#3501 Phase 0: extract ProviderDetailPageClient + smoke test.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract auth-import modals — #3501 Phase 1a (#3634)

#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(db): reclassify localDb unexported modules as intentionally-internal (#3499) (#3635)

Closes #3499 — reclassify localDb unexported modules as intentionally-internal (audit + honest gate framing).

* refactor(db): move call_logs aggregations into callLogStats db module (#3500) (#3636)

#3500 slice 1: call_logs aggregations → src/lib/db/callLogStats.ts (Rule #5). Byte-identical queries; TDD 6/6.

* refactor(dashboard): extract EditCompatibleNodeModal — #3501 Phase 1b (#3638)

#3501 Phase 1b: extract EditCompatibleNodeModal (cycle-safe via leaf constants module).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(db): move community_servers SQL into gamification db module (#3500 slice 3) (#3639)

#3500 slice 3: community_servers SQL → gamification db module.

* refactor(db): move usage_history SQL into usageAnalytics module (#3500 slice 2) (#3644)

#3500 slice 2: usage_history/daily_usage_summary SQL → usageAnalytics db module.

* refactor(db): move skills UPDATE + db-backups SQL into db modules (#3500 slice 5) (#3647)

#3500 slice 5: skills UPDATE (allowlist) + db-backups SQL → db modules.

* refactor(db): move usage_logs/semantic_cache/proxy_logs SQL into db modules (#3500 slice 4) (#3648)

#3500 slice 4: usage_logs/semantic_cache/proxy_logs SQL → db modules. All internal routes done (2 external by-design remain).

* chore(db-gate): reclassify external-DB reads, fully close #3500 (#3649)

Closes #3500: reclassify external-DB reads; all internal raw-SQL migrated to db/ modules.

* refactor(dashboard): extract pure helpers to providerPageHelpers — #3501 Phase 2 (#3653)

#3501 Phase 2: extract pure helpers to providerPageHelpers (leaf, cycle-safe).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract remaining shared helpers to providerPageHelpers — #3501 Phase 2b (#3658)

#3501 Phase 2b: extract remaining shared helpers to providerPageHelpers (leaf, cycle-safe). Heavy modals unblocked.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(reasoning): replay reasoning_content on plain DeepSeek turns (#1682) (#3632)

Integrated into release/v3.8.22

* fix(kiro): route enterprise IAM Identity Center accounts to their regional endpoint (#3631)

Integrated into release/v3.8.22

* refactor: small code cleanup (#3523)

Integrated into release/v3.8.22

* fix(combo): skip same-provider targets on 408/500/502/503/504/524 errors (#3637)

Integrated into release/v3.8.22 — circuit-breaker guard added in review (#1731v2)

* feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (#3659)

Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live.

* Log Responses WebSocket calls in history (#3616)

Integrated into release/v3.8.22 — Codex Responses WebSocket call history logging.

* Add Claude Code routing preference for unprefixed Claude models (#3540)

Integrated into release/v3.8.22 — page.tsx conflict resolved (re-applied toggle to ProviderDetailPageClient) + disable-test updated for catalog drift in review.

* docs(changelog): credit #3632/#3631/#3637/#3659/#3540/#3616/#3523 (v3.8.22 targeted review round)

* fix(mimocode): add required authHeader:"none" to registry entry (#3659 follow-up)

The mimocode RegistryEntry omitted the required authHeader field, which broke
typecheck:core (TS2741). Match the no-auth convention (authType:"none" + authHeader:"none")
used by veoaifree-web and other free providers. Follow-up to #3659 (@pizzav-xyz).

* fix(responses): detect stream readiness for tool-call-only and object-less chunks (#3612) (#3661)

Closes #3612

* fix(mitm): remove duplicated 'Command failed:' error prefix (#3641) (#3662)

Closes #3641

* fix(cli): honor HERMES_HOME for Hermes Agent config path (#3628) (#3663)

Closes #3628

* fix(api): fetch live OpenCode model catalog for no-auth model picker (#3611) (#3664)

Closes #3611

* fix(api): flag provider topology error state by current status, not stale history (#3619) (#3666)

Closes #3619

* fix(electron): launch peer-stamping server-ws.mjs entrypoint to avoid 403 LOCAL_ONLY (#3386) (#3665)

Closes #3386

* fix(dashboard): restore home topology live in-flight pulse (#3507) (#3667)

Closes #3507

* fix(oauth): name Kiro/AWS auto-imported accounts and dedupe by profileArn (#3615) (#3671)

Closes #3615

* fix(resilience): clear stale transient connection cooldowns on startup (#3625) (#3672)

Closes #3625

* fix(i18n): use logical CSS direction utilities for sidebar and key overlays (RTL #3541) (#3670)

Closes #3541

* fix(dashboard): honor auto-hide and switch to visible filter on passthrough Test-all (#3610) (#3669)

Closes #3610

* refactor(dashboard): extract AddApiKeyModal + EditConnectionModal — #3501 Phase 1c (#3674)

#3501 Phase 1c: extract AddApiKeyModal, EditConnectionModal, WebSessionCredentialGuide into components/; god-component 10,166->8,092 LOC. Reconciles the v3.8.22 file-size drift for this file.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* docs(changelog): reconcile v3.8.22 — credit #3621/#3622 + MiMoCode follow-up roll-up

* refactor(dashboard): extract ConnectionRow + ModelCompatPopover + SiliconFlowEndpointModal — #3501 Phase 1d (#3676)

#3501 Phase 1d: god-component 8,092->6,838 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* feat(obsidian): add WebDAV config route + encrypt creds at rest (#3485 part 1) (#3677)

Part 1 of #3485. Adds /api/settings/obsidian/webdav (GET/POST/DELETE) wiring the ready obsidianSync lib, encrypts webdav password + obsidian token at rest, removes the duplicate UI block, drops the KNOWN_MISSING entry. WebDAV file server is part 2.

* feat(obsidian): add /api/v1/webdav file server for Obsidian vault sync (#3485 part 2) (#3678)

Part 2 of #3485. WebDAV server (PROPFIND/GET/PUT/DELETE/MKCOL/MOVE/OPTIONS) handled in the custom server layer (standalone-server-ws.mjs) since the App Router cannot export WebDAV methods. Basic-Auth (constant-time), path-traversal hardened, password decrypt ported from encryption.ts (parity-tested), DATA_DIR resolution parity-tested against dataPaths.ts. End-to-end Obsidian-over-Tailscale validation is a live VPS step (Rule #18).

* fix(combo): stop premature context compaction — real auto-combo windows + per-target compression limit (#3680)

Integrated into release/v3.8.22

* feat(dashboard): deactivate/activate accounts from the quota overview (#3675)

Integrated into release/v3.8.22

* fix(dashboard): close review gaps in bulk provider connection actions (#3271 follow-up) (#3673)

Integrated into release/v3.8.22 — page.tsx conflict (god-component split #3501) resolved by re-applying the bulk-action deltas to ProviderDetailPageClient.tsx

* refactor(dashboard): extract useModelCompatState hook + model sections — #3501 Phase 1e (#3683)

#3501 Phase 1e: extract useModelCompatState hook (unblocks the model sections) + ModelRow/PassthroughModelsSection/PassthroughModelRow/CustomModelsSection/CompatibleModelsSection. god-component 6,838->4,921 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract useProviderConnections/Settings/Models hooks — #3501 Phase 1f (#3684)

#3501 Phase 1f: god-component 4,948->4,062 LOC. Connection state+handlers, settings, and model metadata moved into hooks/.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* chore(release): v3.8.22 CHANGELOG + env-doc sync

- Set release date in CHANGELOG [3.8.22] to 2026-06-11
- Add HERMES_HOME to .env.example (from #3628/#3663)
- Add HERMES_HOME + OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS to ENVIRONMENT.md (#3628/#3540)

* docs(changelog): credit #3673 + #3675 — leninejunior bulk-actions + quota-toggle

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: Abhishek Divekar <adivekar@utexas.edu>
Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: kkkayye <98376609+kkkayye@users.noreply.github.com>
Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
Co-authored-by: Lenine Júnior <lenine@engrene.com.br>
oyi77 added a commit to oyi77/OmniRoute that referenced this pull request Jun 17, 2026
 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
oyi77 added a commit to oyi77/OmniRoute that referenced this pull request Jun 18, 2026
 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
* chore(release): open v3.8.22 development cycle

* refactor(dashboard): extract ProviderDetailPageClient — cheaper-inference#3501 Phase 0 (cheaper-inference#3633)

cheaper-inference#3501 Phase 0: extract ProviderDetailPageClient + smoke test.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract auth-import modals — cheaper-inference#3501 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(db): reclassify localDb unexported modules as intentionally-internal (cheaper-inference#3499) (cheaper-inference#3635)

Closes cheaper-inference#3499 — reclassify localDb unexported modules as intentionally-internal (audit + honest gate framing).

* refactor(db): move call_logs aggregations into callLogStats db module (cheaper-inference#3500) (cheaper-inference#3636)

cheaper-inference#3500 slice 1: call_logs aggregations → src/lib/db/callLogStats.ts (Rule cheaper-inference#5). Byte-identical queries; TDD 6/6.

* refactor(dashboard): extract EditCompatibleNodeModal — cheaper-inference#3501 Phase 1b (cheaper-inference#3638)

cheaper-inference#3501 Phase 1b: extract EditCompatibleNodeModal (cycle-safe via leaf constants module).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(db): move community_servers SQL into gamification db module (cheaper-inference#3500 slice 3) (cheaper-inference#3639)

cheaper-inference#3500 slice 3: community_servers SQL → gamification db module.

* refactor(db): move usage_history SQL into usageAnalytics module (cheaper-inference#3500 slice 2) (cheaper-inference#3644)

cheaper-inference#3500 slice 2: usage_history/daily_usage_summary SQL → usageAnalytics db module.

* refactor(db): move skills UPDATE + db-backups SQL into db modules (cheaper-inference#3500 slice 5) (cheaper-inference#3647)

cheaper-inference#3500 slice 5: skills UPDATE (allowlist) + db-backups SQL → db modules.

* refactor(db): move usage_logs/semantic_cache/proxy_logs SQL into db modules (cheaper-inference#3500 slice 4) (cheaper-inference#3648)

cheaper-inference#3500 slice 4: usage_logs/semantic_cache/proxy_logs SQL → db modules. All internal routes done (2 external by-design remain).

* chore(db-gate): reclassify external-DB reads, fully close cheaper-inference#3500 (cheaper-inference#3649)

Closes cheaper-inference#3500: reclassify external-DB reads; all internal raw-SQL migrated to db/ modules.

* refactor(dashboard): extract pure helpers to providerPageHelpers — cheaper-inference#3501 Phase 2 (cheaper-inference#3653)

cheaper-inference#3501 Phase 2: extract pure helpers to providerPageHelpers (leaf, cycle-safe).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract remaining shared helpers to providerPageHelpers — cheaper-inference#3501 Phase 2b (cheaper-inference#3658)

cheaper-inference#3501 Phase 2b: extract remaining shared helpers to providerPageHelpers (leaf, cycle-safe). Heavy modals unblocked.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(reasoning): replay reasoning_content on plain DeepSeek turns (cheaper-inference#1682) (cheaper-inference#3632)

Integrated into release/v3.8.22

* fix(kiro): route enterprise IAM Identity Center accounts to their regional endpoint (cheaper-inference#3631)

Integrated into release/v3.8.22

* refactor: small code cleanup (cheaper-inference#3523)

Integrated into release/v3.8.22

* fix(combo): skip same-provider targets on 408/500/502/503/504/524 errors (cheaper-inference#3637)

Integrated into release/v3.8.22 — circuit-breaker guard added in review (#1731v2)

* feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (cheaper-inference#3659)

Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live.

* Log Responses WebSocket calls in history (cheaper-inference#3616)

Integrated into release/v3.8.22 — Codex Responses WebSocket call history logging.

* Add Claude Code routing preference for unprefixed Claude models (cheaper-inference#3540)

Integrated into release/v3.8.22 — page.tsx conflict resolved (re-applied toggle to ProviderDetailPageClient) + disable-test updated for catalog drift in review.

* docs(changelog): credit cheaper-inference#3632/cheaper-inference#3631/cheaper-inference#3637/cheaper-inference#3659/cheaper-inference#3540/cheaper-inference#3616/cheaper-inference#3523 (v3.8.22 targeted review round)

* fix(mimocode): add required authHeader:"none" to registry entry (cheaper-inference#3659 follow-up)

The mimocode RegistryEntry omitted the required authHeader field, which broke
typecheck:core (TS2741). Match the no-auth convention (authType:"none" + authHeader:"none")
used by veoaifree-web and other free providers. Follow-up to cheaper-inference#3659 (@pizzav-xyz).

* fix(responses): detect stream readiness for tool-call-only and object-less chunks (cheaper-inference#3612) (cheaper-inference#3661)

Closes cheaper-inference#3612

* fix(mitm): remove duplicated 'Command failed:' error prefix (cheaper-inference#3641) (cheaper-inference#3662)

Closes cheaper-inference#3641

* fix(cli): honor HERMES_HOME for Hermes Agent config path (cheaper-inference#3628) (cheaper-inference#3663)

Closes cheaper-inference#3628

* fix(api): fetch live OpenCode model catalog for no-auth model picker (cheaper-inference#3611) (cheaper-inference#3664)

Closes cheaper-inference#3611

* fix(api): flag provider topology error state by current status, not stale history (cheaper-inference#3619) (cheaper-inference#3666)

Closes cheaper-inference#3619

* fix(electron): launch peer-stamping server-ws.mjs entrypoint to avoid 403 LOCAL_ONLY (cheaper-inference#3386) (cheaper-inference#3665)

Closes cheaper-inference#3386

* fix(dashboard): restore home topology live in-flight pulse (cheaper-inference#3507) (cheaper-inference#3667)

Closes cheaper-inference#3507

* fix(oauth): name Kiro/AWS auto-imported accounts and dedupe by profileArn (cheaper-inference#3615) (cheaper-inference#3671)

Closes cheaper-inference#3615

* fix(resilience): clear stale transient connection cooldowns on startup (cheaper-inference#3625) (cheaper-inference#3672)

Closes cheaper-inference#3625

* fix(i18n): use logical CSS direction utilities for sidebar and key overlays (RTL cheaper-inference#3541) (cheaper-inference#3670)

Closes cheaper-inference#3541

* fix(dashboard): honor auto-hide and switch to visible filter on passthrough Test-all (cheaper-inference#3610) (cheaper-inference#3669)

Closes cheaper-inference#3610

* refactor(dashboard): extract AddApiKeyModal + EditConnectionModal — cheaper-inference#3501 Phase 1c (cheaper-inference#3674)

cheaper-inference#3501 Phase 1c: extract AddApiKeyModal, EditConnectionModal, WebSessionCredentialGuide into components/; god-component 10,166->8,092 LOC. Reconciles the v3.8.22 file-size drift for this file.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* docs(changelog): reconcile v3.8.22 — credit cheaper-inference#3621/cheaper-inference#3622 + MiMoCode follow-up roll-up

* refactor(dashboard): extract ConnectionRow + ModelCompatPopover + SiliconFlowEndpointModal — cheaper-inference#3501 Phase 1d (cheaper-inference#3676)

cheaper-inference#3501 Phase 1d: god-component 8,092->6,838 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* feat(obsidian): add WebDAV config route + encrypt creds at rest (cheaper-inference#3485 part 1) (cheaper-inference#3677)

Part 1 of cheaper-inference#3485. Adds /api/settings/obsidian/webdav (GET/POST/DELETE) wiring the ready obsidianSync lib, encrypts webdav password + obsidian token at rest, removes the duplicate UI block, drops the KNOWN_MISSING entry. WebDAV file server is part 2.

* feat(obsidian): add /api/v1/webdav file server for Obsidian vault sync (cheaper-inference#3485 part 2) (cheaper-inference#3678)

Part 2 of cheaper-inference#3485. WebDAV server (PROPFIND/GET/PUT/DELETE/MKCOL/MOVE/OPTIONS) handled in the custom server layer (standalone-server-ws.mjs) since the App Router cannot export WebDAV methods. Basic-Auth (constant-time), path-traversal hardened, password decrypt ported from encryption.ts (parity-tested), DATA_DIR resolution parity-tested against dataPaths.ts. End-to-end Obsidian-over-Tailscale validation is a live VPS step (Rule cheaper-inference#18).

* fix(combo): stop premature context compaction — real auto-combo windows + per-target compression limit (cheaper-inference#3680)

Integrated into release/v3.8.22

* feat(dashboard): deactivate/activate accounts from the quota overview (cheaper-inference#3675)

Integrated into release/v3.8.22

* fix(dashboard): close review gaps in bulk provider connection actions (cheaper-inference#3271 follow-up) (cheaper-inference#3673)

Integrated into release/v3.8.22 — page.tsx conflict (god-component split cheaper-inference#3501) resolved by re-applying the bulk-action deltas to ProviderDetailPageClient.tsx

* refactor(dashboard): extract useModelCompatState hook + model sections — cheaper-inference#3501 Phase 1e (cheaper-inference#3683)

cheaper-inference#3501 Phase 1e: extract useModelCompatState hook (unblocks the model sections) + ModelRow/PassthroughModelsSection/PassthroughModelRow/CustomModelsSection/CompatibleModelsSection. god-component 6,838->4,921 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract useProviderConnections/Settings/Models hooks — cheaper-inference#3501 Phase 1f (cheaper-inference#3684)

cheaper-inference#3501 Phase 1f: god-component 4,948->4,062 LOC. Connection state+handlers, settings, and model metadata moved into hooks/.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* chore(release): v3.8.22 CHANGELOG + env-doc sync

- Set release date in CHANGELOG [3.8.22] to 2026-06-11
- Add HERMES_HOME to .env.example (from cheaper-inference#3628/cheaper-inference#3663)
- Add HERMES_HOME + OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS to ENVIRONMENT.md (cheaper-inference#3628/cheaper-inference#3540)

* docs(changelog): credit cheaper-inference#3673 + cheaper-inference#3675 — leninejunior bulk-actions + quota-toggle

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: Abhishek Divekar <adivekar@utexas.edu>
Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: kkkayye <98376609+kkkayye@users.noreply.github.com>
Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
Co-authored-by: Lenine Júnior <lenine@engrene.com.br>
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
* chore(release): open v3.8.22 development cycle

* refactor(dashboard): extract ProviderDetailPageClient — cheaper-inference#3501 Phase 0 (cheaper-inference#3633)

cheaper-inference#3501 Phase 0: extract ProviderDetailPageClient + smoke test.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract auth-import modals — cheaper-inference#3501 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(db): reclassify localDb unexported modules as intentionally-internal (cheaper-inference#3499) (cheaper-inference#3635)

Closes cheaper-inference#3499 — reclassify localDb unexported modules as intentionally-internal (audit + honest gate framing).

* refactor(db): move call_logs aggregations into callLogStats db module (cheaper-inference#3500) (cheaper-inference#3636)

cheaper-inference#3500 slice 1: call_logs aggregations → src/lib/db/callLogStats.ts (Rule cheaper-inference#5). Byte-identical queries; TDD 6/6.

* refactor(dashboard): extract EditCompatibleNodeModal — cheaper-inference#3501 Phase 1b (cheaper-inference#3638)

cheaper-inference#3501 Phase 1b: extract EditCompatibleNodeModal (cycle-safe via leaf constants module).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(db): move community_servers SQL into gamification db module (cheaper-inference#3500 slice 3) (cheaper-inference#3639)

cheaper-inference#3500 slice 3: community_servers SQL → gamification db module.

* refactor(db): move usage_history SQL into usageAnalytics module (cheaper-inference#3500 slice 2) (cheaper-inference#3644)

cheaper-inference#3500 slice 2: usage_history/daily_usage_summary SQL → usageAnalytics db module.

* refactor(db): move skills UPDATE + db-backups SQL into db modules (cheaper-inference#3500 slice 5) (cheaper-inference#3647)

cheaper-inference#3500 slice 5: skills UPDATE (allowlist) + db-backups SQL → db modules.

* refactor(db): move usage_logs/semantic_cache/proxy_logs SQL into db modules (cheaper-inference#3500 slice 4) (cheaper-inference#3648)

cheaper-inference#3500 slice 4: usage_logs/semantic_cache/proxy_logs SQL → db modules. All internal routes done (2 external by-design remain).

* chore(db-gate): reclassify external-DB reads, fully close cheaper-inference#3500 (cheaper-inference#3649)

Closes cheaper-inference#3500: reclassify external-DB reads; all internal raw-SQL migrated to db/ modules.

* refactor(dashboard): extract pure helpers to providerPageHelpers — cheaper-inference#3501 Phase 2 (cheaper-inference#3653)

cheaper-inference#3501 Phase 2: extract pure helpers to providerPageHelpers (leaf, cycle-safe).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract remaining shared helpers to providerPageHelpers — cheaper-inference#3501 Phase 2b (cheaper-inference#3658)

cheaper-inference#3501 Phase 2b: extract remaining shared helpers to providerPageHelpers (leaf, cycle-safe). Heavy modals unblocked.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(reasoning): replay reasoning_content on plain DeepSeek turns (cheaper-inference#1682) (cheaper-inference#3632)

Integrated into release/v3.8.22

* fix(kiro): route enterprise IAM Identity Center accounts to their regional endpoint (cheaper-inference#3631)

Integrated into release/v3.8.22

* refactor: small code cleanup (cheaper-inference#3523)

Integrated into release/v3.8.22

* fix(combo): skip same-provider targets on 408/500/502/503/504/524 errors (cheaper-inference#3637)

Integrated into release/v3.8.22 — circuit-breaker guard added in review (#1731v2)

* feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (cheaper-inference#3659)

Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live.

* Log Responses WebSocket calls in history (cheaper-inference#3616)

Integrated into release/v3.8.22 — Codex Responses WebSocket call history logging.

* Add Claude Code routing preference for unprefixed Claude models (cheaper-inference#3540)

Integrated into release/v3.8.22 — page.tsx conflict resolved (re-applied toggle to ProviderDetailPageClient) + disable-test updated for catalog drift in review.

* docs(changelog): credit cheaper-inference#3632/cheaper-inference#3631/cheaper-inference#3637/cheaper-inference#3659/cheaper-inference#3540/cheaper-inference#3616/cheaper-inference#3523 (v3.8.22 targeted review round)

* fix(mimocode): add required authHeader:"none" to registry entry (cheaper-inference#3659 follow-up)

The mimocode RegistryEntry omitted the required authHeader field, which broke
typecheck:core (TS2741). Match the no-auth convention (authType:"none" + authHeader:"none")
used by veoaifree-web and other free providers. Follow-up to cheaper-inference#3659 (@pizzav-xyz).

* fix(responses): detect stream readiness for tool-call-only and object-less chunks (cheaper-inference#3612) (cheaper-inference#3661)

Closes cheaper-inference#3612

* fix(mitm): remove duplicated 'Command failed:' error prefix (cheaper-inference#3641) (cheaper-inference#3662)

Closes cheaper-inference#3641

* fix(cli): honor HERMES_HOME for Hermes Agent config path (cheaper-inference#3628) (cheaper-inference#3663)

Closes cheaper-inference#3628

* fix(api): fetch live OpenCode model catalog for no-auth model picker (cheaper-inference#3611) (cheaper-inference#3664)

Closes cheaper-inference#3611

* fix(api): flag provider topology error state by current status, not stale history (cheaper-inference#3619) (cheaper-inference#3666)

Closes cheaper-inference#3619

* fix(electron): launch peer-stamping server-ws.mjs entrypoint to avoid 403 LOCAL_ONLY (cheaper-inference#3386) (cheaper-inference#3665)

Closes cheaper-inference#3386

* fix(dashboard): restore home topology live in-flight pulse (cheaper-inference#3507) (cheaper-inference#3667)

Closes cheaper-inference#3507

* fix(oauth): name Kiro/AWS auto-imported accounts and dedupe by profileArn (cheaper-inference#3615) (cheaper-inference#3671)

Closes cheaper-inference#3615

* fix(resilience): clear stale transient connection cooldowns on startup (cheaper-inference#3625) (cheaper-inference#3672)

Closes cheaper-inference#3625

* fix(i18n): use logical CSS direction utilities for sidebar and key overlays (RTL cheaper-inference#3541) (cheaper-inference#3670)

Closes cheaper-inference#3541

* fix(dashboard): honor auto-hide and switch to visible filter on passthrough Test-all (cheaper-inference#3610) (cheaper-inference#3669)

Closes cheaper-inference#3610

* refactor(dashboard): extract AddApiKeyModal + EditConnectionModal — cheaper-inference#3501 Phase 1c (cheaper-inference#3674)

cheaper-inference#3501 Phase 1c: extract AddApiKeyModal, EditConnectionModal, WebSessionCredentialGuide into components/; god-component 10,166->8,092 LOC. Reconciles the v3.8.22 file-size drift for this file.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* docs(changelog): reconcile v3.8.22 — credit cheaper-inference#3621/cheaper-inference#3622 + MiMoCode follow-up roll-up

* refactor(dashboard): extract ConnectionRow + ModelCompatPopover + SiliconFlowEndpointModal — cheaper-inference#3501 Phase 1d (cheaper-inference#3676)

cheaper-inference#3501 Phase 1d: god-component 8,092->6,838 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* feat(obsidian): add WebDAV config route + encrypt creds at rest (cheaper-inference#3485 part 1) (cheaper-inference#3677)

Part 1 of cheaper-inference#3485. Adds /api/settings/obsidian/webdav (GET/POST/DELETE) wiring the ready obsidianSync lib, encrypts webdav password + obsidian token at rest, removes the duplicate UI block, drops the KNOWN_MISSING entry. WebDAV file server is part 2.

* feat(obsidian): add /api/v1/webdav file server for Obsidian vault sync (cheaper-inference#3485 part 2) (cheaper-inference#3678)

Part 2 of cheaper-inference#3485. WebDAV server (PROPFIND/GET/PUT/DELETE/MKCOL/MOVE/OPTIONS) handled in the custom server layer (standalone-server-ws.mjs) since the App Router cannot export WebDAV methods. Basic-Auth (constant-time), path-traversal hardened, password decrypt ported from encryption.ts (parity-tested), DATA_DIR resolution parity-tested against dataPaths.ts. End-to-end Obsidian-over-Tailscale validation is a live VPS step (Rule cheaper-inference#18).

* fix(combo): stop premature context compaction — real auto-combo windows + per-target compression limit (cheaper-inference#3680)

Integrated into release/v3.8.22

* feat(dashboard): deactivate/activate accounts from the quota overview (cheaper-inference#3675)

Integrated into release/v3.8.22

* fix(dashboard): close review gaps in bulk provider connection actions (cheaper-inference#3271 follow-up) (cheaper-inference#3673)

Integrated into release/v3.8.22 — page.tsx conflict (god-component split cheaper-inference#3501) resolved by re-applying the bulk-action deltas to ProviderDetailPageClient.tsx

* refactor(dashboard): extract useModelCompatState hook + model sections — cheaper-inference#3501 Phase 1e (cheaper-inference#3683)

cheaper-inference#3501 Phase 1e: extract useModelCompatState hook (unblocks the model sections) + ModelRow/PassthroughModelsSection/PassthroughModelRow/CustomModelsSection/CompatibleModelsSection. god-component 6,838->4,921 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract useProviderConnections/Settings/Models hooks — cheaper-inference#3501 Phase 1f (cheaper-inference#3684)

cheaper-inference#3501 Phase 1f: god-component 4,948->4,062 LOC. Connection state+handlers, settings, and model metadata moved into hooks/.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* chore(release): v3.8.22 CHANGELOG + env-doc sync

- Set release date in CHANGELOG [3.8.22] to 2026-06-11
- Add HERMES_HOME to .env.example (from cheaper-inference#3628/cheaper-inference#3663)
- Add HERMES_HOME + OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS to ENVIRONMENT.md (cheaper-inference#3628/cheaper-inference#3540)

* docs(changelog): credit cheaper-inference#3673 + cheaper-inference#3675 — leninejunior bulk-actions + quota-toggle

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: Abhishek Divekar <adivekar@utexas.edu>
Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: kkkayye <98376609+kkkayye@users.noreply.github.com>
Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
Co-authored-by: Lenine Júnior <lenine@engrene.com.br>
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
* chore(release): open v3.8.22 development cycle

* refactor(dashboard): extract ProviderDetailPageClient — cheaper-inference#3501 Phase 0 (cheaper-inference#3633)

cheaper-inference#3501 Phase 0: extract ProviderDetailPageClient + smoke test.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract auth-import modals — cheaper-inference#3501 Phase 1a (cheaper-inference#3634)

cheaper-inference#3501 Phase 1a: extract 3 auth-import modal clusters.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(db): reclassify localDb unexported modules as intentionally-internal (cheaper-inference#3499) (cheaper-inference#3635)

Closes cheaper-inference#3499 — reclassify localDb unexported modules as intentionally-internal (audit + honest gate framing).

* refactor(db): move call_logs aggregations into callLogStats db module (cheaper-inference#3500) (cheaper-inference#3636)

cheaper-inference#3500 slice 1: call_logs aggregations → src/lib/db/callLogStats.ts (Rule cheaper-inference#5). Byte-identical queries; TDD 6/6.

* refactor(dashboard): extract EditCompatibleNodeModal — cheaper-inference#3501 Phase 1b (cheaper-inference#3638)

cheaper-inference#3501 Phase 1b: extract EditCompatibleNodeModal (cycle-safe via leaf constants module).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(db): move community_servers SQL into gamification db module (cheaper-inference#3500 slice 3) (cheaper-inference#3639)

cheaper-inference#3500 slice 3: community_servers SQL → gamification db module.

* refactor(db): move usage_history SQL into usageAnalytics module (cheaper-inference#3500 slice 2) (cheaper-inference#3644)

cheaper-inference#3500 slice 2: usage_history/daily_usage_summary SQL → usageAnalytics db module.

* refactor(db): move skills UPDATE + db-backups SQL into db modules (cheaper-inference#3500 slice 5) (cheaper-inference#3647)

cheaper-inference#3500 slice 5: skills UPDATE (allowlist) + db-backups SQL → db modules.

* refactor(db): move usage_logs/semantic_cache/proxy_logs SQL into db modules (cheaper-inference#3500 slice 4) (cheaper-inference#3648)

cheaper-inference#3500 slice 4: usage_logs/semantic_cache/proxy_logs SQL → db modules. All internal routes done (2 external by-design remain).

* chore(db-gate): reclassify external-DB reads, fully close cheaper-inference#3500 (cheaper-inference#3649)

Closes cheaper-inference#3500: reclassify external-DB reads; all internal raw-SQL migrated to db/ modules.

* refactor(dashboard): extract pure helpers to providerPageHelpers — cheaper-inference#3501 Phase 2 (cheaper-inference#3653)

cheaper-inference#3501 Phase 2: extract pure helpers to providerPageHelpers (leaf, cycle-safe).

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract remaining shared helpers to providerPageHelpers — cheaper-inference#3501 Phase 2b (cheaper-inference#3658)

cheaper-inference#3501 Phase 2b: extract remaining shared helpers to providerPageHelpers (leaf, cycle-safe). Heavy modals unblocked.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* fix(reasoning): replay reasoning_content on plain DeepSeek turns (cheaper-inference#1682) (cheaper-inference#3632)

Integrated into release/v3.8.22

* fix(kiro): route enterprise IAM Identity Center accounts to their regional endpoint (cheaper-inference#3631)

Integrated into release/v3.8.22

* refactor: small code cleanup (cheaper-inference#3523)

Integrated into release/v3.8.22

* fix(combo): skip same-provider targets on 408/500/502/503/504/524 errors (cheaper-inference#3637)

Integrated into release/v3.8.22 — circuit-breaker guard added in review (#1731v2)

* feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (cheaper-inference#3659)

Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live.

* Log Responses WebSocket calls in history (cheaper-inference#3616)

Integrated into release/v3.8.22 — Codex Responses WebSocket call history logging.

* Add Claude Code routing preference for unprefixed Claude models (cheaper-inference#3540)

Integrated into release/v3.8.22 — page.tsx conflict resolved (re-applied toggle to ProviderDetailPageClient) + disable-test updated for catalog drift in review.

* docs(changelog): credit cheaper-inference#3632/cheaper-inference#3631/cheaper-inference#3637/cheaper-inference#3659/cheaper-inference#3540/cheaper-inference#3616/cheaper-inference#3523 (v3.8.22 targeted review round)

* fix(mimocode): add required authHeader:"none" to registry entry (cheaper-inference#3659 follow-up)

The mimocode RegistryEntry omitted the required authHeader field, which broke
typecheck:core (TS2741). Match the no-auth convention (authType:"none" + authHeader:"none")
used by veoaifree-web and other free providers. Follow-up to cheaper-inference#3659 (@pizzav-xyz).

* fix(responses): detect stream readiness for tool-call-only and object-less chunks (cheaper-inference#3612) (cheaper-inference#3661)

Closes cheaper-inference#3612

* fix(mitm): remove duplicated 'Command failed:' error prefix (cheaper-inference#3641) (cheaper-inference#3662)

Closes cheaper-inference#3641

* fix(cli): honor HERMES_HOME for Hermes Agent config path (cheaper-inference#3628) (cheaper-inference#3663)

Closes cheaper-inference#3628

* fix(api): fetch live OpenCode model catalog for no-auth model picker (cheaper-inference#3611) (cheaper-inference#3664)

Closes cheaper-inference#3611

* fix(api): flag provider topology error state by current status, not stale history (cheaper-inference#3619) (cheaper-inference#3666)

Closes cheaper-inference#3619

* fix(electron): launch peer-stamping server-ws.mjs entrypoint to avoid 403 LOCAL_ONLY (cheaper-inference#3386) (cheaper-inference#3665)

Closes cheaper-inference#3386

* fix(dashboard): restore home topology live in-flight pulse (cheaper-inference#3507) (cheaper-inference#3667)

Closes cheaper-inference#3507

* fix(oauth): name Kiro/AWS auto-imported accounts and dedupe by profileArn (cheaper-inference#3615) (cheaper-inference#3671)

Closes cheaper-inference#3615

* fix(resilience): clear stale transient connection cooldowns on startup (cheaper-inference#3625) (cheaper-inference#3672)

Closes cheaper-inference#3625

* fix(i18n): use logical CSS direction utilities for sidebar and key overlays (RTL cheaper-inference#3541) (cheaper-inference#3670)

Closes cheaper-inference#3541

* fix(dashboard): honor auto-hide and switch to visible filter on passthrough Test-all (cheaper-inference#3610) (cheaper-inference#3669)

Closes cheaper-inference#3610

* refactor(dashboard): extract AddApiKeyModal + EditConnectionModal — cheaper-inference#3501 Phase 1c (cheaper-inference#3674)

cheaper-inference#3501 Phase 1c: extract AddApiKeyModal, EditConnectionModal, WebSessionCredentialGuide into components/; god-component 10,166->8,092 LOC. Reconciles the v3.8.22 file-size drift for this file.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* docs(changelog): reconcile v3.8.22 — credit cheaper-inference#3621/cheaper-inference#3622 + MiMoCode follow-up roll-up

* refactor(dashboard): extract ConnectionRow + ModelCompatPopover + SiliconFlowEndpointModal — cheaper-inference#3501 Phase 1d (cheaper-inference#3676)

cheaper-inference#3501 Phase 1d: god-component 8,092->6,838 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* feat(obsidian): add WebDAV config route + encrypt creds at rest (cheaper-inference#3485 part 1) (cheaper-inference#3677)

Part 1 of cheaper-inference#3485. Adds /api/settings/obsidian/webdav (GET/POST/DELETE) wiring the ready obsidianSync lib, encrypts webdav password + obsidian token at rest, removes the duplicate UI block, drops the KNOWN_MISSING entry. WebDAV file server is part 2.

* feat(obsidian): add /api/v1/webdav file server for Obsidian vault sync (cheaper-inference#3485 part 2) (cheaper-inference#3678)

Part 2 of cheaper-inference#3485. WebDAV server (PROPFIND/GET/PUT/DELETE/MKCOL/MOVE/OPTIONS) handled in the custom server layer (standalone-server-ws.mjs) since the App Router cannot export WebDAV methods. Basic-Auth (constant-time), path-traversal hardened, password decrypt ported from encryption.ts (parity-tested), DATA_DIR resolution parity-tested against dataPaths.ts. End-to-end Obsidian-over-Tailscale validation is a live VPS step (Rule cheaper-inference#18).

* fix(combo): stop premature context compaction — real auto-combo windows + per-target compression limit (cheaper-inference#3680)

Integrated into release/v3.8.22

* feat(dashboard): deactivate/activate accounts from the quota overview (cheaper-inference#3675)

Integrated into release/v3.8.22

* fix(dashboard): close review gaps in bulk provider connection actions (cheaper-inference#3271 follow-up) (cheaper-inference#3673)

Integrated into release/v3.8.22 — page.tsx conflict (god-component split cheaper-inference#3501) resolved by re-applying the bulk-action deltas to ProviderDetailPageClient.tsx

* refactor(dashboard): extract useModelCompatState hook + model sections — cheaper-inference#3501 Phase 1e (cheaper-inference#3683)

cheaper-inference#3501 Phase 1e: extract useModelCompatState hook (unblocks the model sections) + ModelRow/PassthroughModelsSection/PassthroughModelRow/CustomModelsSection/CompatibleModelsSection. god-component 6,838->4,921 LOC.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* refactor(dashboard): extract useProviderConnections/Settings/Models hooks — cheaper-inference#3501 Phase 1f (cheaper-inference#3684)

cheaper-inference#3501 Phase 1f: god-component 4,948->4,062 LOC. Connection state+handlers, settings, and model metadata moved into hooks/.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>

* chore(release): v3.8.22 CHANGELOG + env-doc sync

- Set release date in CHANGELOG [3.8.22] to 2026-06-11
- Add HERMES_HOME to .env.example (from cheaper-inference#3628/cheaper-inference#3663)
- Add HERMES_HOME + OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS to ENVIRONMENT.md (cheaper-inference#3628/cheaper-inference#3540)

* docs(changelog): credit cheaper-inference#3673 + cheaper-inference#3675 — leninejunior bulk-actions + quota-toggle

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: Abhishek Divekar <adivekar@utexas.edu>
Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: kkkayye <98376609+kkkayye@users.noreply.github.com>
Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
Co-authored-by: Lenine Júnior <lenine@engrene.com.br>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant