g1t/apps/web/app/routes/home.tsx

156 lines5,739 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Initial g1t: services, event bus, intents and attempts1import { env } from "cloudflare:workers";
API and MCP server, Rust identity service, registration, site redesign2import { ArrowRight, Plus } from "lucide-react";
Initial g1t: services, event bus, intents and attempts3import { Link } from "react-router";
4
5import type { Route } from "./+types/home";
API and MCP server, Rust identity service, registration, site redesign6import { Landing } from "../components/landing";
7import { RepoList } from "../components/repo-list";
8import {
9 Avatar,
10 ButtonLink,
11 CopyLine,
12 EmptyState,
13 Status,
14 TimeAgo,
15} from "../components/ui";
Initial g1t: services, event bus, intents and attempts16import { getViewer } from "../lib/session.server";
17
18export function meta({}: Route.MetaArgs) {
19 return [
API and MCP server, Rust identity service, registration, site redesign20 { title: "g1t — a git forge built for agents" },
Initial g1t: services, event bus, intents and attempts21 {
22 name: "description",
23 content:
API and MCP server, Rust identity service, registration, site redesign24 "State a goal, let any number of agents attempt it in parallel, each in its own fork, and land the one that works. Open source, built on Cloudflare.",
Initial g1t: services, event bus, intents and attempts25 },
26 ];
27}
28
29export async function loader({ context }: Route.LoaderArgs) {
30 const viewer = getViewer(context);
31 const [repos, attempts] = await Promise.all([
API and MCP server, Rust identity service, registration, site redesign32 env.REPOS.list(viewer, viewer ? { namespace: viewer.username } : {}),
Initial g1t: services, event bus, intents and attempts33 env.WORK.listActiveAttempts(viewer),
34 ]);
35 // Mission control links to each attempt under its repo.
36 const attemptRepos = await Promise.all(
37 attempts.map(({ attempt }) => env.REPOS.getById(attempt.repoId, viewer)),
38 );
39 return {
40 viewer,
41 repos,
42 active: attempts.flatMap((item, i) => {
43 const repo = attemptRepos[i];
44 return repo.ok ? [{ ...item, repo: repo.value }] : [];
45 }),
46 };
47}
48
49export default function Home({ loaderData }: Route.ComponentProps) {
50 const { viewer, repos, active } = loaderData;
API and MCP server, Rust identity service, registration, site redesign51 if (!viewer) return <Landing repos={repos} />;
Initial g1t: services, event bus, intents and attempts52
API and MCP server, Rust identity service, registration, site redesign53 const working = active.filter(({ attempt }) => attempt.status === "working");
54 return (
55 <main className="mx-auto grid max-w-6xl gap-10 px-4 py-10 lg:grid-cols-[1fr_20rem]">
56 <div className="min-w-0 space-y-10">
Initial g1t: services, event bus, intents and attempts57 <section>
API and MCP server, Rust identity service, registration, site redesign58 <div className="flex items-center gap-3">
59 <Avatar name={viewer.username} size={36} />
60 <div>
61 <h1 className="text-xl font-semibold tracking-tight">
62 Mission control
63 </h1>
64 <p className="text-sm text-muted">
65 {working.length === 0
66 ? "Nothing is running right now."
67 : `${working.length} ${working.length === 1 ? "attempt is" : "attempts are"} running.`}
68 </p>
69 </div>
70 </div>
71 </section>
72
73 <section>
74 <h2 className="text-sm font-medium text-muted">In progress</h2>
75 <div className="mt-3">
76 {active.length === 0 ? (
77 <EmptyState title="No attempts in progress">
78 Open an intent on a repository and start an attempt, or point
79 your agent at one.
80 </EmptyState>
81 ) : (
82 <ul className="divide-y divide-line overflow-hidden rounded-xl border border-line bg-surface">
83 {active.map(({ attempt, intent, repo }) => (
84 <li key={attempt.id}>
85 <Link
86 to={`/${repo.namespace}/${repo.name}/attempts/${attempt.id}`}
87 className="flex items-center gap-4 px-4 py-3 transition-colors hover:bg-raised"
88 >
89 <span className="min-w-0 grow">
90 <span className="block truncate font-medium">
91 {intent.title}
92 </span>
93 <span className="font-mono text-xs text-muted">
94 {repo.namespace}/{repo.name} #{intent.number} · attempt{" "}
95 {attempt.number} · {attempt.agent}
96 </span>
97 </span>
98 <span className="shrink-0 text-xs text-faint">
99 <TimeAgo at={attempt.updatedAt} />
Initial g1t: services, event bus, intents and attempts100 </span>
API and MCP server, Rust identity service, registration, site redesign101 <Status value={attempt.status} />
102 </Link>
103 </li>
104 ))}
105 </ul>
106 )}
107 </div>
Initial g1t: services, event bus, intents and attempts108 </section>
API and MCP server, Rust identity service, registration, site redesign109
Initial g1t: services, event bus, intents and attempts110 <section>
API and MCP server, Rust identity service, registration, site redesign111 <div className="flex items-center justify-between">
112 <h2 className="text-sm font-medium text-muted">Your repositories</h2>
113 <ButtonLink to="/new" variant="quiet">
114 <Plus size={14} />
115 New
116 </ButtonLink>
117 </div>
Initial g1t: services, event bus, intents and attempts118 <RepoList repos={repos} />
119 </section>
API and MCP server, Rust identity service, registration, site redesign120 </div>
Initial g1t: services, event bus, intents and attempts121
API and MCP server, Rust identity service, registration, site redesign122 <aside className="space-y-4">
123 <div className="rounded-xl border border-line bg-surface p-5">
124 <h2 className="font-medium">Connect an agent</h2>
125 <p className="mt-1.5 text-sm text-muted">
126 Create an access token in settings, then add g1t to Claude Code.
127 </p>
128 <div className="mt-4 space-y-2">
129 <CopyLine
130 prompt
131 text='claude mcp add --transport http g1t https://mcp.g1t.sh --header "Authorization: Bearer $G1T_TOKEN"'
132 />
133 </div>
134 <Link
135 to="/docs/agents"
136 className="mt-4 inline-flex items-center gap-1 text-sm text-accent hover:underline"
137 >
138 How it works <ArrowRight size={13} />
139 </Link>
140 </div>
141 <div className="rounded-xl border border-line bg-surface p-5">
142 <h2 className="font-medium">Explore</h2>
143 <p className="mt-1.5 text-sm text-muted">
144 Browse public repositories and the intents open on them.
145 </p>
146 <Link
147 to="/explore"
148 className="mt-3 inline-flex items-center gap-1 text-sm text-accent hover:underline"
149 >
150 Public repositories <ArrowRight size={13} />
151 </Link>
152 </div>
153 </aside>
Initial g1t: services, event bus, intents and attempts154 </main>
155 );
156}