feat: restructure as pnpm monorepo with Tauri desktop shell

- Migrate to packages/web + packages/desktop workspace layout via git mv
- Add Tauri v2 desktop shell with @tauri-apps/plugin-http for CORS bypass
- Configure Turborepo with package-level dependsOn build graph
- Add semantic-release with exec plugin for GHA output and disabled PR comments
- Fix http:default capability scope to allow all HTTP/HTTPS origins
- Add Vite Tauri integration (clearScreen, TAURI_DEV_HOST, target, envPrefix)
- Add semantic-release.yml and release.yml GitHub Actions workflows
- Fix all Biome lint errors (noArrayIndexKey, noNonNullAssertion, button types)
This commit is contained in:
Offending Commit
2026-04-24 16:52:40 -05:00
parent 9a74182f97
commit 92c4dfd3dd
152 changed files with 14088 additions and 4774 deletions

View File

@@ -0,0 +1,43 @@
import { Sidebar } from "@/components/layout/Sidebar";
import { loadConfig } from "@/lib/config";
import { applyTheme, getStoredTheme } from "@/lib/theme";
import { Outlet, createRootRoute, useRouter } from "@tanstack/react-router";
import { useEffect } from "react";
function RootLayout() {
const config = loadConfig();
const router = useRouter();
const isSettings = router.state.location.pathname === "/settings";
useEffect(() => {
applyTheme(getStoredTheme());
}, []);
useEffect(() => {
if (!config && !isSettings) {
router.navigate({ to: "/settings" as never });
}
}, [config, isSettings, router]);
if (isSettings) {
return <Outlet />;
}
if (!config) return null;
return (
<div
className="flex h-screen w-full overflow-hidden"
style={{ background: "var(--bg)", position: "relative", zIndex: 1 }}
>
<Sidebar />
<main className="flex-1 overflow-auto" style={{ position: "relative", zIndex: 1 }}>
<Outlet />
</main>
</div>
);
}
export const Route = createRootRoute({
component: RootLayout,
});

View File

@@ -0,0 +1,6 @@
import { Dashboard } from "@/components/dashboard/Dashboard";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/")({
component: Dashboard,
});

View File

@@ -0,0 +1,48 @@
import { SettingsForm } from "@/components/settings/SettingsForm";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { motion } from "framer-motion";
import { Brain } from "lucide-react";
export const Route = createFileRoute("/settings")({
component: SettingsPage,
});
function SettingsPage() {
const navigate = useNavigate();
return (
<div
className="flex-1 flex items-center justify-center p-4 overflow-auto"
style={{ background: "var(--bg)" }}
>
<motion.div
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ type: "spring", stiffness: 260, damping: 24 }}
className="w-full max-w-md"
>
<div className="mb-8 text-center">
<div
className="w-14 h-14 rounded-2xl flex items-center justify-center mx-auto mb-4"
style={{
background: "linear-gradient(135deg, #4f46e5, #7c3aed)",
boxShadow: "0 0 32px rgba(99,102,241,0.35)",
}}
>
<Brain className="w-7 h-7 text-white" strokeWidth={2} />
</div>
<h1 className="text-2xl font-semibold tracking-tight" style={{ color: "var(--text-1)" }}>
Honcho UI
</h1>
<p className="text-sm mt-1" style={{ color: "var(--text-3)" }}>
Connect to your self-hosted Honcho instance
</p>
</div>
<SettingsForm onSaved={() => navigate({ to: "/" as never })} />
<p className="text-xs text-center mt-4" style={{ color: "var(--text-4)" }}>
Connection details are stored locally on this device only
</p>
</motion.div>
</div>
);
}

View File

@@ -0,0 +1,6 @@
import { WorkspaceList } from "@/components/workspaces/WorkspaceList";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces")({
component: WorkspaceList,
});

View File

@@ -0,0 +1,6 @@
import { WorkspaceDetail } from "@/components/workspaces/WorkspaceDetail";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId")({
component: WorkspaceDetail,
});

View File

@@ -0,0 +1,6 @@
import { ConclusionBrowser } from "@/components/conclusions/ConclusionBrowser";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/conclusions")({
component: ConclusionBrowser,
});

View File

@@ -0,0 +1,6 @@
import { PeerList } from "@/components/peers/PeerList";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers")({
component: PeerList,
});

View File

@@ -0,0 +1,6 @@
import { PeerDetail } from "@/components/peers/PeerDetail";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers_/$peerId")({
component: PeerDetail,
});

View File

@@ -0,0 +1,6 @@
import { ChatPage } from "@/components/chat/ChatPage";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers_/$peerId_/chat")({
component: ChatPage,
});

View File

@@ -0,0 +1,6 @@
import { SessionList } from "@/components/sessions/SessionList";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/sessions")({
component: SessionList,
});

View File

@@ -0,0 +1,6 @@
import { SessionDetail } from "@/components/sessions/SessionDetail";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/sessions_/$sessionId")({
component: SessionDetail,
});

View File

@@ -0,0 +1,11 @@
import { WebhookManager } from "@/components/workspaces/WebhookManager";
import { createFileRoute, useParams } from "@tanstack/react-router";
export const Route = createFileRoute("/workspaces_/$workspaceId_/webhooks")({
component: WebhookManagerPage,
});
function WebhookManagerPage() {
const { workspaceId } = useParams({ strict: false }) as { workspaceId: string };
return <WebhookManager workspaceId={workspaceId} />;
}