Fork Horse repository, listed by its owner. Publisher snapshot.
packages/forkhorse-gatekeeper/app/picker.ts
Snapshot at 34e3175
1import { followSystemTheme } from "../../forkhorse-dashboard/src/theme.ts";
2import { RpcTarget, newMessagePortRpcSession } from "capnweb";
3import "./picker.css";
4import { mountForkPicker } from "../../forkhorse-dashboard/src/picker.tsx";
5interface Fork {
6 url: string;
7 repoName: string;
8 head: string;
9}
10interface Host extends RpcTarget {
11 gatekeeper: { list(): Promise<Fork[]> };
12 getInitialResource(): Promise<{ resourceUrl: string; resourceUrlPattern: string } | null>;
13 setSelectionReady(ready: boolean): Promise<void>;
14 resize(height: number, layoutHeight: number): Promise<void>;
15}
16let selected: string | undefined;
17let forks: Fork[] = [];
18class Picker extends RpcTarget {
19 async collectResourceUrl(): Promise<string> {
20 if (!selected || !forks.some((f) => f.url === selected))
21 throw new Error("Select an agent fork.");
22 return selected;
23 }
24 updateViewport(): void {}
25 windowResized(): void {}
26}
27const channel = new MessageChannel();
28window.parent.postMessage({ type: "handshake" }, "*", [channel.port2]);
29const host = newMessagePortRpcSession<Host>(channel.port1, new Picker());
30const root = document.getElementById("sidebar")!;
31const picker = mountForkPicker(root, (url) => {
32 selected = url;
33 picker.render(forks, selected, "Only forks owned by your connected agent are listed.");
34 void host.setSelectionReady(forks.some((f) => f.url === selected));
35});
36picker.render([], undefined, "Loading your forks…", true);
37void (async () => {
38 await host.setSelectionReady(false);
39 forks = await host.gatekeeper.list();
40 const initial = await host.getInitialResource();
41 if (initial && forks.some((f) => f.url === initial.resourceUrl)) {
42 selected = initial.resourceUrl;
43 await host.setSelectionReady(true);
44 }
45 picker.render(
46 forks,
47 selected,
48 forks.length
49 ? "Only forks owned by your connected agent are listed."
50 : "This agent has no forks yet.",
51 );
52 await host.resize(300, 300);
53})().catch(() => {
54 picker.render([], undefined, "Fork discovery unavailable. Reconnect your agent.");
55});
56window.addEventListener(
57 "pagehide",
58 () => {
59 picker.dispose();
60 host[Symbol.dispose]();
61 channel.port1.close();
62 },
63 { once: true },
64);
65
66const stopTheme = followSystemTheme();
67window.addEventListener("pagehide", stopTheme, { once: true });
68