diff --git a/.env.example b/.env.example
index 599f1ab2d3..089b87379c 100644
--- a/.env.example
+++ b/.env.example
@@ -209,6 +209,14 @@ CLOUD_URL=
# Public-facing base URL — CRITICAL for reverse proxy / OAuth callback setups.
# Used by: OAuth redirect_uri computation, Dashboard UI links, cloud/model sync.
# Set to your public URL when behind nginx/Caddy (e.g., https://omniroute.example.com).
+#
+# Dashboard display behavior: when this variable is unset, the dashboard
+# auto-detects the base URL shown in curl examples and CLI tool snippets
+# from window.location.origin (the host the user is browsing). Setting it
+# explicitly is only required when running behind a reverse proxy with a
+# different public hostname, or when OAuth callbacks must point to a
+# canonical URL.
+#
# Default: http://localhost:20128
NEXT_PUBLIC_BASE_URL=http://localhost:20128
diff --git a/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.tsx b/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.tsx
index 2b2c8d27c3..126d75b215 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.tsx
+++ b/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.tsx
@@ -21,6 +21,7 @@ import {
CustomCliCard,
} from "./components";
import { useTranslations } from "next-intl";
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL;
const AUTO_CONFIGURED_TOOL_IDS = new Set([
@@ -226,7 +227,7 @@ export default function CLIToolsPageClient({ machineId: _machineId }) {
if (typeof window !== "undefined") {
return window.location.origin;
}
- return "http://localhost:20128";
+ return DEFAULT_DISPLAY_BASE_URL;
};
if (loading || !statusesLoaded) {
diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/ClineToolCard.tsx b/src/app/(dashboard)/dashboard/cli-tools/components/ClineToolCard.tsx
index 8e61118c7c..e079a4e77d 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/components/ClineToolCard.tsx
+++ b/src/app/(dashboard)/dashboard/cli-tools/components/ClineToolCard.tsx
@@ -5,6 +5,7 @@ import { Card, Button, ModelSelectModal, ManualConfigModal } from "@/shared/comp
import Image from "next/image";
import CliStatusBadge from "./CliStatusBadge";
import { useTranslations } from "next-intl";
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL;
@@ -147,7 +148,7 @@ export default function ClineToolCard({
const getEffectiveBaseUrl = () => {
if (customBaseUrl) return customBaseUrl;
- return baseUrl || "http://localhost:20128";
+ return baseUrl || DEFAULT_DISPLAY_BASE_URL;
};
const handleApply = async () => {
diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/CustomCliCard.tsx b/src/app/(dashboard)/dashboard/cli-tools/components/CustomCliCard.tsx
index 1726de6025..e0119498ba 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/components/CustomCliCard.tsx
+++ b/src/app/(dashboard)/dashboard/cli-tools/components/CustomCliCard.tsx
@@ -9,6 +9,7 @@ import {
buildCustomCliJsonConfig,
normalizeOpenAiBaseUrl,
} from "./customCliConfig";
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
interface ModelOption {
value: string;
@@ -59,7 +60,7 @@ export default function CustomCliCard({
(!cloudEnabled
? "sk_omniroute"
: translateOrFallback("yourApiKeyPlaceholder", "sk-your-omniroute-key"));
- const baseUrlWithV1 = normalizeOpenAiBaseUrl(baseUrl || "http://localhost:20128");
+ const baseUrlWithV1 = normalizeOpenAiBaseUrl(baseUrl || DEFAULT_DISPLAY_BASE_URL);
const chatCompletionsEndpoint = `${baseUrlWithV1}/chat/completions`;
const envScript = useMemo(
diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.tsx b/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.tsx
index 89e976fa65..95f7074efa 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.tsx
+++ b/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.tsx
@@ -7,6 +7,7 @@ import { useTranslations } from "next-intl";
import { copyToClipboard } from "@/shared/utils/clipboard";
import { buildOpenCodeConfigDocument } from "@/shared/services/opencodeConfig";
import { useTheme } from "@/shared/hooks/useTheme";
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
export default function DefaultToolCard({
toolId,
@@ -90,7 +91,7 @@ export default function DefaultToolCard({
[getSelectedModelEntries]
);
- const normalizedBaseUrl = baseUrl || "http://localhost:20128";
+ const normalizedBaseUrl = baseUrl || DEFAULT_DISPLAY_BASE_URL;
const baseUrlWithV1 = normalizedBaseUrl.endsWith("/v1")
? normalizedBaseUrl
: `${normalizedBaseUrl}/v1`;
diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/KiloToolCard.tsx b/src/app/(dashboard)/dashboard/cli-tools/components/KiloToolCard.tsx
index 52cfd85391..e99243968b 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/components/KiloToolCard.tsx
+++ b/src/app/(dashboard)/dashboard/cli-tools/components/KiloToolCard.tsx
@@ -5,6 +5,7 @@ import { Card, Button, ModelSelectModal, ManualConfigModal } from "@/shared/comp
import Image from "next/image";
import CliStatusBadge from "./CliStatusBadge";
import { useTranslations } from "next-intl";
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
const CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL;
@@ -133,7 +134,7 @@ export default function KiloToolCard({
const getEffectiveBaseUrl = () => {
if (customBaseUrl) return customBaseUrl;
- return baseUrl || "http://localhost:20128";
+ return baseUrl || DEFAULT_DISPLAY_BASE_URL;
};
const handleApply = async () => {
diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/customCliConfig.ts b/src/app/(dashboard)/dashboard/cli-tools/components/customCliConfig.ts
index 82488084a2..b3c205f768 100644
--- a/src/app/(dashboard)/dashboard/cli-tools/components/customCliConfig.ts
+++ b/src/app/(dashboard)/dashboard/cli-tools/components/customCliConfig.ts
@@ -1,3 +1,5 @@
+import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
+
export interface CustomCliAliasMapping {
alias: string;
model: string;
@@ -12,7 +14,7 @@ export interface CustomCliConfigInput {
}
export function normalizeOpenAiBaseUrl(baseUrl: string): string {
- const trimmed = (baseUrl || "http://localhost:20128").trim().replace(/\/+$/, "");
+ const trimmed = (baseUrl || DEFAULT_DISPLAY_BASE_URL).trim().replace(/\/+$/, "");
return trimmed.endsWith("/v1") ? trimmed : `${trimmed}/v1`;
}
diff --git a/src/app/(dashboard)/dashboard/endpoint/ApiEndpointsTab.tsx b/src/app/(dashboard)/dashboard/endpoint/ApiEndpointsTab.tsx
index 1bfaee3f81..4f9b8c9b83 100644
--- a/src/app/(dashboard)/dashboard/endpoint/ApiEndpointsTab.tsx
+++ b/src/app/(dashboard)/dashboard/endpoint/ApiEndpointsTab.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect, useMemo } from "react";
import { Card } from "@/shared/components";
+import { useDisplayBaseUrl } from "@/shared/hooks";
/* ─── Types ──────────────────────────────────────────── */
interface Endpoint {
@@ -65,6 +66,7 @@ const WEBHOOK_EVENTS = [
/* ─── Main Component ─────────────────────────────────── */
export default function ApiEndpointsTab() {
+ const baseUrl = useDisplayBaseUrl();
const [catalog, setCatalog] = useState
- curl -X {ep.method} http://localhost:20128
+ curl -X {ep.method} {baseUrl}
{ep.path.replace("/api/", "/")}
{ep.security ? ' -H "Authorization: Bearer YOUR_KEY"' : ""}
{ep.requestBody
diff --git a/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx b/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx
index 10f3e25412..3be6a00ca1 100644
--- a/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx
+++ b/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx
@@ -4,6 +4,7 @@ import { useState, useEffect, useMemo, useCallback } from "react";
import Link from "next/link";
import { Card, Button, Input, Modal, CardSkeleton, SegmentedControl } from "@/shared/components";
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
+import { useDisplayBaseUrl } from "@/shared/hooks";
import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
import { useTranslations } from "next-intl";
@@ -1007,7 +1008,8 @@ export default function APIPageClient({ machineId }: APIPageClientProps) {
}
}, [fetchTailscaleStatus, handleTailscaleEnable, tailscalePassword, translateOrFallback]);
- const [baseUrl, setBaseUrl] = useState("/v1");
+ const displayBaseUrl = useDisplayBaseUrl();
+ const baseUrl = `${displayBaseUrl}/v1`;
const normalizedCloudBaseUrl = cloudBaseUrl
? resolvedMachineId && !cloudBaseUrl.endsWith(`/${resolvedMachineId}`)
? `${cloudBaseUrl}/${resolvedMachineId}`
@@ -1015,14 +1017,6 @@ export default function APIPageClient({ machineId }: APIPageClientProps) {
: null;
const cloudEndpointNew = normalizedCloudBaseUrl ? `${normalizedCloudBaseUrl}/v1` : null;
- // Hydration fix: Only access window on client side
- useEffect(() => {
- if (typeof window !== "undefined") {
- const defaultOrigin = process.env.NEXT_PUBLIC_BASE_URL || window.location.origin;
- setBaseUrl(`${defaultOrigin}/v1`);
- }
- }, []);
-
if (loading) {
return (
diff --git a/src/app/(dashboard)/dashboard/endpoint/__tests__/ApiEndpointsTab.test.tsx b/src/app/(dashboard)/dashboard/endpoint/__tests__/ApiEndpointsTab.test.tsx
index ce993e3663..8b7aa4e33f 100644
--- a/src/app/(dashboard)/dashboard/endpoint/__tests__/ApiEndpointsTab.test.tsx
+++ b/src/app/(dashboard)/dashboard/endpoint/__tests__/ApiEndpointsTab.test.tsx
@@ -104,4 +104,48 @@ describe("ApiEndpointsTab", () => {
expect(document.body.textContent).toContain("1 endpoints across 1 categories");
expect(document.body.textContent).toContain("/api/v1/chat/completions");
});
+
+ it("renders curl example using window.location.origin when NEXT_PUBLIC_BASE_URL is unset", async () => {
+ fetchMock.mockResolvedValue(
+ jsonResponse({
+ info: { title: "OmniRoute API", version: "3.7.6" },
+ servers: [],
+ tags: [{ name: "Chat" }],
+ endpoints: [
+ {
+ method: "POST",
+ path: "/api/v1/chat/completions",
+ tags: ["Chat"],
+ summary: "Create chat completion",
+ description: "Create chat completion",
+ security: false,
+ parameters: [],
+ requestBody: false,
+ responses: ["200"],
+ },
+ ],
+ schemas: [],
+ })
+ );
+
+ renderApiEndpointsTab();
+
+ await waitForText("OmniRoute API");
+
+ // Expand the endpoint to reveal the curl example
+ const endpointRow = document.body.querySelector("code.font-mono.flex-1");
+ if (endpointRow?.parentElement) {
+ await act(async () => {
+ endpointRow.parentElement!.click();
+ });
+ }
+
+ // After mount the hook swaps DEFAULT_DISPLAY_BASE_URL for window.location.origin.
+ // In jsdom the default origin is "http://localhost".
+ const expectedOrigin = window.location.origin; // "http://localhost" in jsdom
+ await waitForText(`curl -X POST ${expectedOrigin}/v1/chat/completions`);
+ expect(document.body.textContent).toContain(
+ `curl -X POST ${expectedOrigin}/v1/chat/completions`
+ );
+ });
});
diff --git a/src/app/(dashboard)/dashboard/onboarding/page.tsx b/src/app/(dashboard)/dashboard/onboarding/page.tsx
index 71995da7f7..df80edcaa5 100644
--- a/src/app/(dashboard)/dashboard/onboarding/page.tsx
+++ b/src/app/(dashboard)/dashboard/onboarding/page.tsx
@@ -3,6 +3,7 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
+import { useDisplayBaseUrl } from "@/shared/hooks";
const STEP_IDS = ["welcome", "security", "provider", "test", "done"];
const STEP_ICONS = ["waving_hand", "lock", "dns", "play_circle", "check_circle"];
@@ -20,9 +21,10 @@ export default function OnboardingWizard() {
const router = useRouter();
const t = useTranslations("onboarding");
const tc = useTranslations("common");
+ const baseUrl = useDisplayBaseUrl();
const [step, setStep] = useState(0);
const [loading, setLoading] = useState(true);
- const [apiEndpoint, setApiEndpoint] = useState("http://localhost:20128/api/v1");
+ const [apiEndpoint, setApiEndpoint] = useState(`${baseUrl}/api/v1`);
// Security step state
const [password, setPassword] = useState("");
diff --git a/src/app/landing/components/GetStarted.tsx b/src/app/landing/components/GetStarted.tsx
index 2fa01f4195..9eb847d475 100644
--- a/src/app/landing/components/GetStarted.tsx
+++ b/src/app/landing/components/GetStarted.tsx
@@ -2,12 +2,13 @@
import { useState } from "react";
import { useTranslations } from "next-intl";
import { copyToClipboard } from "@/shared/utils/clipboard";
+import { useDisplayBaseUrl } from "@/shared/hooks";
export default function GetStarted() {
const t = useTranslations("landing");
const [copied, setCopied] = useState(false);
- const endpoint = "http://localhost:20128";
+ const endpoint = useDisplayBaseUrl();
const dashboardUrl = `${endpoint}/dashboard`;
const command = "npx omniroute";
diff --git a/src/shared/hooks/__tests__/useDisplayBaseUrl.test.tsx b/src/shared/hooks/__tests__/useDisplayBaseUrl.test.tsx
new file mode 100644
index 0000000000..c6dd92b137
--- /dev/null
+++ b/src/shared/hooks/__tests__/useDisplayBaseUrl.test.tsx
@@ -0,0 +1,176 @@
+// @vitest-environment jsdom
+import React, { act } from "react";
+import { createRoot } from "react-dom/client";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { DEFAULT_DISPLAY_BASE_URL } from "../useDisplayBaseUrl";
+
+const cleanupCallbacks: Array<() => void> = [];
+
+function makeContainer(): HTMLElement {
+ const container = document.createElement("div");
+ document.body.appendChild(container);
+ cleanupCallbacks.push(() => {
+ container.remove();
+ });
+ return container;
+}
+
+describe("useDisplayBaseUrl", () => {
+ beforeEach(() => {
+ (
+ globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
+ ).IS_REACT_ACT_ENVIRONMENT = true;
+ });
+
+ afterEach(() => {
+ while (cleanupCallbacks.length > 0) {
+ cleanupCallbacks.pop()?.();
+ }
+ document.body.innerHTML = "";
+ vi.unstubAllEnvs();
+ vi.unstubAllGlobals();
+ });
+
+ it("returns env value on first render and after mount when NEXT_PUBLIC_BASE_URL is set", async () => {
+ vi.stubEnv("NEXT_PUBLIC_BASE_URL", "https://example.com");
+
+ const { useDisplayBaseUrl } = await import("../useDisplayBaseUrl");
+
+ const container = makeContainer();
+ const root = createRoot(container);
+
+ function C() {
+ const url = useDisplayBaseUrl();
+ return {url};
+ }
+
+ // Synchronous act: commits render and flushes synchronous effects.
+ // The queueMicrotask in useEffect has not yet fired.
+ act(() => {
+ root.render( );
+ });
+
+ // Env set: first render shows env value (useEffect no-ops when envValue is set)
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ "https://example.com"
+ );
+
+ // Flush microtasks and any remaining async work
+ await act(async () => {});
+
+ // Env still wins after mount
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ "https://example.com"
+ );
+ });
+
+ it("returns DEFAULT_DISPLAY_BASE_URL on first render and origin after mount when env unset", async () => {
+ vi.stubEnv("NEXT_PUBLIC_BASE_URL", "");
+
+ const { useDisplayBaseUrl } = await import("../useDisplayBaseUrl");
+
+ const container = makeContainer();
+ const root = createRoot(container);
+
+ function C() {
+ const url = useDisplayBaseUrl();
+ return {url};
+ }
+
+ // Synchronous act commits render. useEffect fires but queueMicrotask
+ // schedules setState for after this act() call returns.
+ act(() => {
+ root.render( );
+ });
+
+ // Pre-microtask: DOM still shows the initial state (DEFAULT_DISPLAY_BASE_URL)
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ DEFAULT_DISPLAY_BASE_URL
+ );
+
+ // Flush queueMicrotask callback (setState) and resulting re-render
+ await act(async () => {});
+
+ // After mount: swaps to window.location.origin
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ window.location.origin
+ );
+ });
+
+ it("trims and strips trailing slash from env value", async () => {
+ vi.stubEnv("NEXT_PUBLIC_BASE_URL", " https://x.com/ ");
+
+ const { useDisplayBaseUrl } = await import("../useDisplayBaseUrl");
+
+ const container = makeContainer();
+ const root = createRoot(container);
+
+ function C() {
+ const url = useDisplayBaseUrl();
+ return {url};
+ }
+
+ await act(async () => {
+ root.render( );
+ });
+
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe("https://x.com");
+ });
+
+ it("strips trailing slash from window.location.origin after mount", async () => {
+ vi.stubEnv("NEXT_PUBLIC_BASE_URL", "");
+
+ // Stub window.location with trailing slash on origin
+ vi.stubGlobal("location", { origin: "http://192.168.13.62:20128/" });
+
+ const { useDisplayBaseUrl } = await import("../useDisplayBaseUrl");
+
+ const container = makeContainer();
+ const root = createRoot(container);
+
+ function C() {
+ const url = useDisplayBaseUrl();
+ return {url};
+ }
+
+ // Render and flush all effects including queueMicrotask
+ await act(async () => {
+ root.render( );
+ });
+
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ "http://192.168.13.62:20128"
+ );
+ });
+
+ it("treats empty-string env as unset and falls through to origin after mount", async () => {
+ vi.stubEnv("NEXT_PUBLIC_BASE_URL", "");
+
+ const { useDisplayBaseUrl } = await import("../useDisplayBaseUrl");
+
+ const container = makeContainer();
+ const root = createRoot(container);
+
+ function C() {
+ const url = useDisplayBaseUrl();
+ return {url};
+ }
+
+ // Synchronous act: render committed, useEffect fired, microtask queued but not yet run
+ act(() => {
+ root.render( );
+ });
+
+ // Empty env treated as unset → initial state is DEFAULT_DISPLAY_BASE_URL
+ expect(container.querySelector('[data-testid="value"]')?.textContent).toBe(
+ DEFAULT_DISPLAY_BASE_URL
+ );
+
+ // Flush queueMicrotask + re-render
+ await act(async () => {});
+
+ // After mount: resolves to origin
+ const result = container.querySelector('[data-testid="value"]')?.textContent;
+ expect(result).toBe(window.location.origin.replace(/\/+$/, ""));
+ });
+});
diff --git a/src/shared/hooks/index.ts b/src/shared/hooks/index.ts
index 68c81c2d54..896a06fc7e 100644
--- a/src/shared/hooks/index.ts
+++ b/src/shared/hooks/index.ts
@@ -1,2 +1,3 @@
// Shared Hooks - Export all
export { useTheme } from "./useTheme";
+export { useDisplayBaseUrl, DEFAULT_DISPLAY_BASE_URL } from "./useDisplayBaseUrl";
diff --git a/src/shared/hooks/useDisplayBaseUrl.ts b/src/shared/hooks/useDisplayBaseUrl.ts
new file mode 100644
index 0000000000..96081ba583
--- /dev/null
+++ b/src/shared/hooks/useDisplayBaseUrl.ts
@@ -0,0 +1,49 @@
+"use client";
+
+import { useEffect, useState } from "react";
+
+export const DEFAULT_DISPLAY_BASE_URL = "http://localhost:20128";
+
+function normalizeUrl(value?: string): string | null {
+ const trimmed = value?.trim();
+ if (!trimmed) return null;
+ return trimmed.replace(/\/+$/, "");
+}
+
+/**
+ * Returns the public base URL to display in the dashboard.
+ *
+ * Resolution chain:
+ * 1. NEXT_PUBLIC_BASE_URL (env, trimmed + slash-normalized) — wins if set.
+ * 2. window.location.origin after client mount — when env is unset.
+ * 3. DEFAULT_DISPLAY_BASE_URL ("http://localhost:20128") — SSR / first render fallback.
+ *
+ * DISPLAY ONLY — do NOT use this hook for OAuth `redirect_uri`.
+ * OAuth callers must read `process.env.NEXT_PUBLIC_BASE_URL` directly to avoid
+ * host-header attack surface. For server-side resolution, use
+ * `src/shared/utils/resolveOmniRouteBaseUrl.ts` instead.
+ */
+export function useDisplayBaseUrl(): string {
+ const envValue = normalizeUrl(process.env.NEXT_PUBLIC_BASE_URL);
+
+ const [url, setUrl] = useState(envValue ?? DEFAULT_DISPLAY_BASE_URL);
+
+ useEffect(() => {
+ if (envValue) return;
+ const origin = normalizeUrl(window.location.origin) ?? DEFAULT_DISPLAY_BASE_URL;
+ // Schedule via queueMicrotask so setState is called inside a callback,
+ // not synchronously in the effect body (react-hooks/set-state-in-effect).
+ // The unmounted guard prevents a stale setState on a torn-down root
+ // (relevant under React strict mode's double-invoke, where cleanup runs
+ // before the microtask fires on the first effect invocation).
+ let unmounted = false;
+ queueMicrotask(() => {
+ if (!unmounted) setUrl(origin);
+ });
+ return () => {
+ unmounted = true;
+ };
+ }, [envValue]);
+
+ return url;
+}
diff --git a/vitest.config.ts b/vitest.config.ts
index 34b035d509..8fb8eb8c6e 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -9,6 +9,7 @@ export default defineConfig({
include: [
"src/app/**/dashboard/cache/__tests__/**/*.test.tsx",
"src/app/**/dashboard/endpoint/__tests__/**/*.test.tsx",
+ "src/shared/hooks/__tests__/**/*.test.tsx",
"src/lib/memory/__tests__/**/*.test.ts",
"src/lib/skills/__tests__/**/*.test.ts",
"tests/unit/encryption.test.ts",