diff --git a/next.config.mjs b/next.config.mjs index 31644a31..8e848dd2 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -2,10 +2,18 @@ const nextConfig = { output: "standalone", serverExternalPackages: ["better-sqlite3"], + outputFileTracingExcludes: { + "*": [ + "**/Cookies/**", + "**/AppData/Local/**", + "**/node_modules/.cache/**", + ], + }, images: { unoptimized: true }, env: {}, + turbopack: {}, webpack: (config, { isServer }) => { // Ignore fs/path modules in browser bundle if (!isServer) { diff --git a/package.json b/package.json index c21df767..7944a2dc 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "private": true, "scripts": { "dev": "next dev --webpack --port 20128", - "build": "NODE_ENV=production next build --webpack", - "start": "NODE_ENV=production next start", + "build": "cross-env NODE_ENV=production next build", + "start": "cross-env NODE_ENV=production next start", "dev:bun": "bun --bun next dev --webpack --port 20128", "build:bun": "NODE_ENV=production bun --bun next build --webpack", "start:bun": "NODE_ENV=production bun ./.next/standalone/server.js" @@ -44,6 +44,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.1.18", + "cross-env": "^10.1.0", "eslint": "^9", "eslint-config-next": "16.1.6", "postcss": "^8.5.6", diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.js b/src/app/(dashboard)/dashboard/providers/[id]/page.js index 56aaa12b..f64ccd45 100644 --- a/src/app/(dashboard)/dashboard/providers/[id]/page.js +++ b/src/app/(dashboard)/dashboard/providers/[id]/page.js @@ -38,6 +38,7 @@ export default function ProviderDetailPage() { const [providerStrategy, setProviderStrategy] = useState(null); // null = use global, "round-robin" = override const [providerStickyLimit, setProviderStickyLimit] = useState(""); const [suggestedModels, setSuggestedModels] = useState([]); + const [kiloFreeModels, setKiloFreeModels] = useState([]); const { copied, copy } = useCopyToClipboard(); const providerInfo = providerNode @@ -77,6 +78,15 @@ export default function ProviderDetailPage() { } }, []); + // Fetch free models from Kilo API for kilocode provider + useEffect(() => { + if (providerId !== "kilocode") return; + fetch("/api/providers/kilo/free-models") + .then((res) => res.json()) + .then((data) => { if (data.models?.length) setKiloFreeModels(data.models); }) + .catch(() => {}); + }, [providerId]); + const fetchConnections = useCallback(async () => { try { const [connectionsRes, nodesRes, proxyPoolsRes, settingsRes] = await Promise.all([ @@ -537,6 +547,11 @@ export default function ProviderDetailPage() { /> ); } + // Combine hardcoded models with Kilo free models (deduplicated) + const displayModels = [ + ...models, + ...kiloFreeModels.filter((fm) => !models.some((m) => m.id === fm.id)), + ]; // Custom models added by user (stored as aliases: modelId → providerAlias/modelId) const customModels = Object.entries(modelAliases) .filter(([alias, fullModel]) => { @@ -556,7 +571,7 @@ export default function ProviderDetailPage() { return (
{modelId}
{fullModel}
+ {fullModel}
+ {isFree && (
+ Free
+ )}