devist 0.11.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
import { Button } from "@/components/ui/button";
import { useAuth } from "@/contexts/AuthContext";
import {
  ArrowRight,
  Boxes,
  Eye,
  Github,
  LayoutDashboard,
  Terminal,
} from "lucide-react";
import { Link } from "react-router-dom";

const REPO_URL = "https://github.com/WebchemistCorp/devist";

export default function Landing() {
  const { session } = useAuth();

  return (
    <div className="min-h-screen bg-background text-foreground">
      <Header signedIn={!!session} />
      <main>
        <Hero signedIn={!!session} />
        <About />
        <Workflow />
      </main>
      <Footer />
    </div>
  );
}

function Header({ signedIn }: { signedIn: boolean }) {
  return (
    <header className="sticky top-0 z-10 border-b bg-background/80 backdrop-blur">
      <div className="mx-auto max-w-6xl px-6 h-14 flex items-center justify-between">
        <Link to="/" className="flex items-center gap-2 font-semibold">
          <span className="text-base">devist</span>
          <span className="text-xs text-muted-foreground hidden sm:inline">
            Bootstrap. Observe. Iterate.
          </span>
        </Link>
        <nav className="flex items-center gap-2">
          <a
            href={REPO_URL}
            target="_blank"
            rel="noreferrer"
            className="text-sm text-muted-foreground hover:text-foreground p-2 rounded-md hover:bg-muted"
            title="GitHub"
          >
            <Github size={16} />
          </a>
          {signedIn ? (
            <Link to="/dashboard">
              <Button size="sm">Open dashboard</Button>
            </Link>
          ) : (
            <Link to="/login">
              <Button size="sm" variant="ghost">
                Sign in
              </Button>
            </Link>
          )}
        </nav>
      </div>
    </header>
  );
}

function Hero({ signedIn }: { signedIn: boolean }) {
  return (
    <section className="mx-auto max-w-6xl px-6 pt-20 pb-16">
      <div className="max-w-3xl">
        <h1 className="text-4xl sm:text-5xl font-bold tracking-tight">
          Bootstrap. Observe. Iterate.
        </h1>
        <p className="mt-5 text-lg text-muted-foreground leading-relaxed">
          A CLI, a background worker, and this dashboard — together they let
          you spin up new projects from curated templates, watch your code
          change in real time, and have a Claude-powered second pair of eyes
          surface advice as you work.
        </p>
        <div className="mt-8 flex items-center gap-3 flex-wrap">
          <Link to={signedIn ? "/dashboard" : "/login"}>
            <Button size="lg" className="gap-2">
              {signedIn ? "Open dashboard" : "Get started"}
              <ArrowRight size={16} />
            </Button>
          </Link>
          <a href={REPO_URL} target="_blank" rel="noreferrer">
            <Button size="lg" variant="outline" className="gap-2">
              <Github size={16} />
              View on GitHub
            </Button>
          </a>
        </div>

        <pre className="mt-10 rounded-lg border bg-muted/40 p-4 text-sm overflow-x-auto">
          <code>
            <span className="text-muted-foreground"># install once</span>
            {"\n"}
            cargo install devist{"\n\n"}
            <span className="text-muted-foreground"># scaffold + start</span>
            {"\n"}
            devist init my-app --template react-vite{"\n"}
            devist start my-app --dev
          </code>
        </pre>
      </div>
    </section>
  );
}

function About() {
  const cards = [
    {
      icon: <Boxes size={20} />,
      title: "Templates",
      body: "Curated starters for React, FastAPI, Rust-axum, Flutter, NestJS, and more. Each template ships with CLAUDE.md, AGENT.md, and a workspace skeleton — your AI tools know the conventions before you write a line of code.",
    },
    {
      icon: <Eye size={20} />,
      title: "Worker",
      body: "A background daemon watches a parent folder of projects and records every file event into local SQLite. After idle bursts, it asks Claude to extract durable facts (stored in mem0) and surface high-signal advice — with rate limits so it never spams.",
    },
    {
      icon: <LayoutDashboard size={20} />,
      title: "Dashboard",
      body: "This site. Live timeline of every project, severity-colored advice inbox, one-click acknowledge. Pulls from the same Supabase the worker pushes to — review from any device, async.",
    },
  ];

  return (
    <section className="border-t bg-muted/20">
      <div className="mx-auto max-w-6xl px-6 py-16">
        <div className="max-w-2xl">
          <h2 className="text-2xl sm:text-3xl font-bold tracking-tight">
            What is devist?
          </h2>
          <p className="mt-3 text-muted-foreground">
            Three pieces that compose into a single workflow for AI-assisted
            development. Use any one alone; they're better together.
          </p>
        </div>
        <div className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {cards.map((c) => (
            <div
              key={c.title}
              className="rounded-lg border bg-card p-5 space-y-3"
            >
              <div className="inline-flex items-center justify-center w-9 h-9 rounded-md bg-foreground/5">
                {c.icon}
              </div>
              <h3 className="font-semibold">{c.title}</h3>
              <p className="text-sm text-muted-foreground leading-relaxed">
                {c.body}
              </p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function Workflow() {
  const steps = [
    {
      n: "1",
      title: "Install",
      cmd: "cargo install devist",
      hint: "Or `brew install webchemistcorp/devist/devist`. macOS / Linux / Windows.",
    },
    {
      n: "2",
      title: "Scaffold a project",
      cmd: "devist init my-app --template react-vite",
      hint: "Pick from 8+ templates. Add `--var agent_mode=vibe` for a looser AI guide.",
    },
    {
      n: "3",
      title: "Start the worker",
      cmd: "devist worker start",
      hint: "Observes everything under your Workspace folder. Advice lands here.",
    },
  ];

  return (
    <section className="border-t">
      <div className="mx-auto max-w-6xl px-6 py-16">
        <div className="max-w-2xl">
          <h2 className="text-2xl sm:text-3xl font-bold tracking-tight">
            Three commands to get going
          </h2>
          <p className="mt-3 text-muted-foreground">
            From zero to "the worker is observing" in under a minute. Then
            point this dashboard at the same Supabase project to see events
            stream in.
          </p>
        </div>
        <ol className="mt-10 space-y-5">
          {steps.map((s) => (
            <li
              key={s.n}
              className="flex gap-5 items-start rounded-lg border bg-card p-5"
            >
              <div className="shrink-0 inline-flex items-center justify-center w-8 h-8 rounded-full bg-foreground text-background text-sm font-semibold">
                {s.n}
              </div>
              <div className="flex-1 min-w-0 space-y-2">
                <h3 className="font-semibold">{s.title}</h3>
                <pre className="rounded border bg-muted/40 px-3 py-2 text-sm overflow-x-auto">
                  <code className="flex items-center gap-2">
                    <Terminal
                      size={14}
                      className="shrink-0 text-muted-foreground"
                    />
                    {s.cmd}
                  </code>
                </pre>
                <p className="text-sm text-muted-foreground">{s.hint}</p>
              </div>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="border-t">
      <div className="mx-auto max-w-6xl px-6 py-8 flex items-center justify-between text-sm text-muted-foreground">
        <span>devist · Webchemist</span>
        <div className="flex items-center gap-4">
          <a
            href={REPO_URL}
            target="_blank"
            rel="noreferrer"
            className="hover:text-foreground"
          >
            GitHub
          </a>
          <a
            href={`${REPO_URL}/blob/main/LICENSE`}
            target="_blank"
            rel="noreferrer"
            className="hover:text-foreground"
          >
            MIT
          </a>
        </div>
      </div>
    </footer>
  );
}