Initial CodeCraft: web-based coding harness for AI models

Rust backend (axum/tokio): agent loop with streaming, tools (fs, bash,
web_fetch, todo, ask_user, subagents, skills, craft snapshots/compare),
permissions with modes and rules, Anthropic + OpenAI-compatible providers,
MCP client (stdio/HTTP, elicitation), SQLite sessions, usage statistics,
compaction, commented TOML config editable via toml_edit.

React PWA: chat with live streaming, permission/question cards, modes
(build/plan/craft), settings for providers/models/prices/MCP/permissions,
raw config editor, statistics dashboard, i18n (en/de). Docker setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-08 14:39:24 +01:00
commit f3a2fe3816
62 files changed
+21835

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
import { useEffect, useState } from "react";
import { ApiError, connectEvents, get, getToken } from "./api";
import { useT } from "./i18n";
import { navigate, useRoute } from "./router";
import { applyEvent, loadSessions, resync, setState } from "./store";
import { Sidebar } from "./components/Sidebar";
import { Login } from "./components/Login";
import { ChatView } from "./components/ChatView";
import { NewSession } from "./components/NewSession";
import { Settings } from "./components/Settings";
import { Stats } from "./components/Stats";
type AuthState = "checking" | "login" | "ok";
export function App() {
const t = useT();
const route = useRoute();
const [auth, setAuth] = useState<AuthState>("checking");
const [menuOpen, setMenuOpen] = useState(false);
// Check whether a token is needed and whether ours works.
useEffect(() => {
(async () => {
try {
const info = await get<{ auth_required: boolean }>("/info");
if (info.auth_required && !getToken()) return setAuth("login");
await loadSessions();
setAuth("ok");
} catch (e) {
setAuth(e instanceof ApiError && e.status === 401 ? "login" : "ok");
}
})();
}, []);
useEffect(() => {
if (auth !== "ok") return;
return connectEvents({
onEvent: applyEvent,
onOpen: () => {
setState(() => ({ connected: true }));
void resync().catch(() => undefined);
},
onClose: () => setState(() => ({ connected: false })),
});
}, [auth]);
// Close the mobile menu on navigation.
useEffect(() => setMenuOpen(false), [route.join("/")]);
if (auth === "checking") return <div className="empty">{t("common.loading")}</div>;
if (auth === "login") return <Login onSuccess={() => setAuth("ok")} />;
const [section, arg] = route;
let content;
if (section === "s" && arg) content = <ChatView key={arg} sessionId={arg} onMenu={() => setMenuOpen(true)} />;
else if (section === "settings") content = <Settings tab={arg} onMenu={() => setMenuOpen(true)} />;
else if (section === "stats") content = <Stats onMenu={() => setMenuOpen(true)} />;
else content = <NewSession onMenu={() => setMenuOpen(true)} onCreated={(id) => navigate(`/s/${id}`)} />;
return (
<div className="app">
{menuOpen && <div className="backdrop" onClick={() => setMenuOpen(false)} />}
<Sidebar open={menuOpen} activeId={section === "s" ? arg : undefined} section={section ?? ""} />
<main className="main">{content}</main>
</div>
);
}