+ {/* F27: Collapsible think block */}
+ {thinking && (
+
+
+ Show reasoning ({thinking.split(/\s+/).length} words)
+
+
+ {thinking}
+
+
+ )}
+ {/* F25/F26: Markdown with syntax highlighted code blocks */}
+
+
+
+ {match[1]}
+
+
+ {codeString}
+
+
+ );
+ }
+ return (
+
+ {children}
+
+ );
+ },
+ p({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ h1({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ h2({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ h3({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ ul({ children }) {
+ return (
+
+ );
+ },
+ ol({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ li({ children }) {
+ return
{children};
+ },
+ blockquote({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ strong({ children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ em({ children }) {
+ return
{children};
+ },
+ a({ href, children }) {
+ return (
+
+ {children}
+
+ );
+ },
+ }}
+ >
+ {answer || (streaming ? '' : '(empty response)')}
+
+
+ {streaming && (
+
+
+
+ Memory Budget
+
+
+ {formatBytes(totalRam)} unified
+
+
+
+ {/* OS + Apps */}
+
+ {pct(osApps) > 8 ? 'OS' : ''}
+
+ {/* Loaded models */}
+ {runningModels.map((m, i) => (
+
+ {pct(m.size_vram) > 10 ? m.name.split(':')[0] : ''}
+
+ ))}
+ {/* Free */}
+
+ {pct(freeRam) > 8 ? `${formatBytes(freeRam)} free` : ''}
+
+
+ {runningModels.length > 0 && (
+
+ {runningModels.map((m, i) => (
+
+
+ {m.name.split(':')[0]}: {formatBytes(m.size_vram)}
+
+ ))}
+
+ )}
+
+ );
+}
diff --git a/__LOCAL_LLMs/dashboard/src/app/page.tsx b/__LOCAL_LLMs/dashboard/src/app/(mission-control)/mission-control/page.tsx
similarity index 99%
rename from __LOCAL_LLMs/dashboard/src/app/page.tsx
rename to __LOCAL_LLMs/dashboard/src/app/(mission-control)/mission-control/page.tsx
index 5242db58..b9ae8913 100644
--- a/__LOCAL_LLMs/dashboard/src/app/page.tsx
+++ b/__LOCAL_LLMs/dashboard/src/app/(mission-control)/mission-control/page.tsx
@@ -44,17 +44,17 @@ import type {
Toast,
PullProgress,
StreamMetrics,
-} from './lib/types';
+} from '../../lib/types';
import {
formatBytes,
formatUptime,
estimateRam,
checkMemoryFit,
getModelBadges,
-} from './lib/format';
-import { StatusDot } from './components/StatusDot';
-import { ProgressBar } from './components/ProgressBar';
-import { Sparkline } from './components/Sparkline';
+} from '../../lib/format';
+import { StatusDot } from '../../components/StatusDot';
+import { ProgressBar } from '../../components/ProgressBar';
+import { Sparkline } from '../../components/Sparkline';
import { RamBudgetBar } from './components/RamBudgetBar';
import { MarkdownResponse } from './components/MarkdownResponse';
diff --git a/__LOCAL_LLMs/dashboard/src/app/(workspace)/c/[id]/page.tsx b/__LOCAL_LLMs/dashboard/src/app/(workspace)/c/[id]/page.tsx
new file mode 100644
index 00000000..b6ae1314
--- /dev/null
+++ b/__LOCAL_LLMs/dashboard/src/app/(workspace)/c/[id]/page.tsx
@@ -0,0 +1,51 @@
+'use client';
+
+import Link from 'next/link';
+import { useEffect, useState } from 'react';
+import { getConversation, getMessages } from '../../../lib/db';
+import type { Conversation, Message } from '../../../lib/types';
+import { ConversationView } from '../../components/ConversationView';
+
+export default function ConversationPage({ params }: { params: { id: string } }) {
+ const [conversation, setConversation] = useState