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

136 lines4,843 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";
2import { Link } from "react-router";
3
4import type { Repo } from "@g1t/contracts";
5
6import type { Route } from "./+types/home";
7import { Mark } from "../components/logo";
8import { Status, TimeAgo } from "../components/ui";
9import { getViewer } from "../lib/session.server";
10
11export function meta({}: Route.MetaArgs) {
12 return [
13 { title: "g1t — git for many agents at once" },
14 {
15 name: "description",
16 content:
17 "g1t is a git platform built on Cloudflare where many agents attempt the same change in parallel and the best one ships.",
18 },
19 ];
20}
21
22export async function loader({ context }: Route.LoaderArgs) {
23 const viewer = getViewer(context);
24 const [repos, attempts] = await Promise.all([
25 env.REPOS.list(viewer),
26 env.WORK.listActiveAttempts(viewer),
27 ]);
28 // Mission control links to each attempt under its repo.
29 const attemptRepos = await Promise.all(
30 attempts.map(({ attempt }) => env.REPOS.getById(attempt.repoId, viewer)),
31 );
32 return {
33 viewer,
34 repos,
35 active: attempts.flatMap((item, i) => {
36 const repo = attemptRepos[i];
37 return repo.ok ? [{ ...item, repo: repo.value }] : [];
38 }),
39 };
40}
41
42function RepoList({ repos }: { repos: Repo[] }) {
43 if (repos.length === 0) {
44 return <p className="mt-4 text-muted">Nothing here yet.</p>;
45 }
46 return (
47 <ul className="mt-4 divide-y divide-line rounded-md border border-line">
48 {repos.map((repo) => (
49 <li key={repo.id} className="px-4 py-3">
50 <Link
51 to={`/${repo.namespace}/${repo.name}`}
52 className="font-mono text-sm hover:text-accent"
53 >
54 {repo.namespace}/{repo.name}
55 </Link>
56 {repo.isPrivate && (
57 <span className="ml-2 text-xs text-muted">private</span>
58 )}
59 {repo.description && (
60 <p className="mt-1 text-sm text-muted">{repo.description}</p>
61 )}
62 </li>
63 ))}
64 </ul>
65 );
66}
67
68export default function Home({ loaderData }: Route.ComponentProps) {
69 const { viewer, repos, active } = loaderData;
70
71 if (viewer) {
72 return (
73 <main className="mx-auto max-w-5xl space-y-12 px-4 py-12">
74 <section>
75 <h1 className="text-sm font-medium text-muted">In progress</h1>
76 {active.length === 0 ? (
77 <p className="mt-4 rounded-md border border-dashed border-line p-8 text-center text-sm text-muted">
78 No attempts running. Open an intent on a repository to start one.
79 </p>
80 ) : (
81 <ul className="mt-4 divide-y divide-line rounded-md border border-line">
82 {active.map(({ attempt, intent, repo }) => (
83 <li key={attempt.id}>
84 <Link
85 to={`/${repo.namespace}/${repo.name}/attempts/${attempt.id}`}
86 className="flex items-center gap-4 px-4 py-3 hover:bg-surface"
87 >
88 <span className="min-w-0 grow">
89 <span className="block truncate">{intent.title}</span>
90 <span className="font-mono text-xs text-muted">
91 {repo.namespace}/{repo.name} #{intent.number} · attempt{" "}
92 {attempt.number} · {attempt.agent}
93 </span>
94 </span>
95 <span className="shrink-0 text-xs text-muted">
96 <TimeAgo at={attempt.updatedAt} />
97 </span>
98 <Status value={attempt.status} />
99 </Link>
100 </li>
101 ))}
102 </ul>
103 )}
104 </section>
105 <section>
106 <h2 className="text-sm font-medium text-muted">Repositories</h2>
107 <RepoList repos={repos} />
108 </section>
109 </main>
110 );
111 }
112
113 return (
114 <main className="mx-auto max-w-5xl px-4 pb-24">
115 <section className="py-24">
116 <Mark className="size-14" />
117 <h1 className="mt-8 text-4xl font-semibold tracking-tight sm:text-5xl">
118 Many attempts. <span className="text-accent">One ships.</span>
119 </h1>
120 <p className="mt-4 max-w-xl text-lg text-muted">
121 g1t is a git platform for the age of agents. State an intent, let
122 agents attempt it in parallel, compare the results, and ship the best
123 one.
124 </p>
125 <pre className="mt-8 inline-block rounded-md border border-line bg-surface px-4 py-3 font-mono text-sm">
126 git clone https://g1t.sh/<span className="text-muted">owner</span>/
127 <span className="text-muted">repo</span>.git
128 </pre>
129 </section>
130 <section>
131 <h2 className="text-sm font-medium text-muted">Public repositories</h2>
132 <RepoList repos={repos} />
133 </section>
134 </main>
135 );
136}