Skip to content
217 linesCodeBlameRaw
1import type { User } from "./identity";
2import type { RepoPath } from "./repos";
3import type { Result } from "./result";
4
5/**
6 * Self-hosted runners: a workspace's or a repository's own machines, which
7 * run its workflow jobs (and, when it says so, its agents' work) instead of
8 * g1t's sandboxes, at $0. Mirrors `crates/contracts/src/runners.rs`.
9 */
10
11export type RunnerStatus = "online" | "busy" | "offline";
12
13/** What a runner is doing now. */
14export type RunnerWork = {
15 kind: "workflow" | "agent";
16 id: string;
17 name: string;
18 repo: string | null;
19 /** The workflow run the job is in; for `agent` work, the agent run it is, when known. */
20 runId: string | null;
21 startedAt: string | null;
22};
23
24export type Runner = {
25 id: string;
26 name: string;
27 workspace: string;
28 /** `owner/name` for a repository's own runner; null for the workspace's. */
29 repo: string | null;
30 group: string | null;
31 labels: string[];
32 os: "linux" | "macos" | "windows";
33 arch: "x64" | "arm64";
34 version: string;
35 ephemeral: boolean;
36 status: RunnerStatus;
37 work: RunnerWork | null;
38 lastSeenAt: string | null;
39 createdAt: string;
40 createdBy: string | null;
41 /** How it keeps work from its machine, as it last said; null for a runner from before runners said. */
42 isolation?: RunnerIsolation | null;
43};
44
45/**
46 * `nested-container`: a container per job inside the runner's own sandboxed container (or VM).
47 * `vm`: a throwaway VM per job, native to the machine's OS (Windows Sandbox).
48 * `container`: a container per job on a Docker Engine shared with the machine.
49 * `host`: directly on the machine, unsandboxed.
50 */
51export type RunnerIsolation = "nested-container" | "vm" | "container" | "host";
52
53export type RunnerGroup = {
54 id: string;
55 name: string;
56 default: boolean;
57 /** Repository names; empty is every repository in the workspace. */
58 repositories: string[];
59 runners: number;
60 updatedAt: string;
61};
62
63/** Shown once. */
64export type RegistrationToken = {
65 token: string;
66 expiresAt: string;
67 workspace: string;
68 repo: string | null;
69 group: string | null;
70 url: string;
71};
72
73export type RunnerSettings = {
74 agentsOnSelfHosted: boolean;
75 agentLabels: string[];
76 forkPullRequests: boolean;
77 /** For a repository: these are its workspace's. */
78 inherited: boolean;
79};
80
81export type RunnersOwner = { repo: RepoPath } | { workspace: string };
82
83export type RunnerSettingsChange = {
84 agents_on_self_hosted?: boolean;
85 agent_labels?: string[];
86 fork_pull_requests?: boolean;
87 inherit?: boolean;
88};
89
90/** A workflow job running in one of g1t's sandboxes. Snake case, as `runner_activity` answers. */
91export type CloudJob = { id: string; name: string; run_id: string; repo: string; started_at: string | null };
92
93/** Agent work handed to one of the workspace's own runners, waiting for one or taken. */
94export type HandedOverTask = {
95 id: string;
96 /** The agent run it is; null for work handed over before runs were noted. */
97 run_id: string | null;
98 kind: string;
99 title: string;
100 repo: string;
101 status: "queued" | "in_progress";
102 runner_name: string | null;
103 created_at: string;
104 started_at: string | null;
105};
106
107/** What runs for a workspace now, in g1t's sandboxes and on its own runners (`runner_activity`). */
108export type RunnerActivity = {
109 /** At most `RUNNER_ACTIVITY_LIMIT`, newest first. */
110 cloud_jobs: CloudJob[];
111 cloud_jobs_queued: number;
112 handed_over: HandedOverTask[];
113 self_hosted_jobs_queued: number;
114};
115
116/** The most jobs and tasks `runner_activity` lists of each: `ACTIVITY_LIMIT` in the actions service. */
117export const RUNNER_ACTIVITY_LIMIT = 100;
118
119/** A job that has waited ten minutes or more with no matching runner online. */
120export type StuckJob = { id: string; name: string; runId: string; repo: string; labels: string; queuedAt: string };
121
122export interface RunnersApi {
123 /** The viewer's workspaces' jobs stuck waiting for a self-hosted runner, for Mission control. */
124 stuck(viewer: User): Promise<StuckJob[]>;
125 /** What runs for the workspace now, in g1t's sandboxes and handed to its own runners. Owners. */
126 activity(actor: User, workspace: string): Promise<Result<RunnerActivity>>;
127 list(actor: User, owner: RunnersOwner): Promise<Result<Runner[]>>;
128 createToken(actor: User, owner: RunnersOwner, group?: string): Promise<Result<RegistrationToken>>;
129 remove(actor: User, owner: RunnersOwner, id: string): Promise<Result<boolean>>;
130 groups(actor: User, workspace: string): Promise<Result<RunnerGroup[]>>;
131 /** Without `id`, a new group. */
132 setGroup(actor: User, workspace: string, group: { id?: string; name?: string; repositories?: string[] }): Promise<Result<RunnerGroup>>;
133 deleteGroup(actor: User, workspace: string, id: string): Promise<Result<boolean>>;
134 settings(actor: User, owner: RunnersOwner): Promise<Result<RunnerSettings>>;
135 setSettings(actor: User, owner: RunnersOwner, change: RunnerSettingsChange): Promise<Result<RunnerSettings>>;
136 /** What the person's own desktop app says of its runner, in a workspace they own. */
137 reportDesktop(actor: User, report: DesktopReport): Promise<Result<boolean>>;
138 /** The workspace's desktops, as each app last said. Owners. */
139 desktops(actor: User, workspace: string): Promise<Result<DesktopRunner[]>>;
140}
141
142/**
143 * The desktop app keeps a runner on a person's computer while it is open.
144 * What it says of that runner (its state, why, and the fix) comes from one
145 * catalogue in the app (apps/desktop/src-tauri/src/runner/diagnosis.rs),
146 * and the site shows it word for word: `closed` is what to show once g1t
147 * is closed on that computer, which the app sends too.
148 */
149export type DesktopDiagnosis = {
150 code: string;
151 tone: "ok" | "working" | "off" | "warning" | "problem";
152 title: string;
153 cause: string | null;
154 fix: string | null;
155 /** A sandboxed desktop's kinds of job, each with how it is: Linux jobs can run while Windows jobs cannot. */
156 capabilities?: DesktopCapability[];
157};
158
159/** One kind of job a sandboxed desktop runs (`linux`, `windows`, `macos`), as its app says it. */
160export type DesktopCapability = {
161 id: string;
162 /** `Linux jobs`. */
163 label: string;
164 tone: DesktopDiagnosis["tone"];
165 /** `Waiting for jobs`, `Not available`. */
166 title: string;
167 cause: string | null;
168 fix: string | null;
169};
170
171/** How a desktop runs jobs. */
172export type DesktopBackend = "sandboxed" | "docker" | "host";
173
174export type DesktopReport = {
175 workspace: string;
176 machine: string;
177 backend: DesktopBackend;
178 version: string | null;
179 diagnosis: DesktopDiagnosis;
180 closed: DesktopDiagnosis;
181};
182
183/** One person's computer, as its desktop app last said. */
184export type DesktopRunner = {
185 workspace: string;
186 machine: string;
187 /** Whose computer: their username. */
188 person: string;
189 backend: DesktopBackend;
190 version: string | null;
191 diagnosis: DesktopDiagnosis;
192 closed: DesktopDiagnosis;
193 /** Heard from in the last ten minutes: g1t is open there. */
194 open: boolean;
195 reportedAt: string;
196};
197
198/** The label every desktop app's runner has. */
199export const DESKTOP_LABEL = "desktop";
200
201/**
202 * The runner's container image: `g1t-runner` and the Docker CLI, for
203 * running it in Docker or Kubernetes. Published with each release.
204 */
205export const RUNNER_IMAGE = "g1t.sh/flagon-io/g1t-runner";
206
207/** Where the runner binary is published: `g1t.sh/downloads/runner/<version>/<file>`. */
208export const RUNNER_DOWNLOADS = "https://g1t.sh/downloads/runner";
209
210/** The file for each platform, as published. */
211export const RUNNER_FILES: Record<"linux-x64" | "linux-arm64" | "macos-arm64" | "macos-x64" | "windows-x64", string> = {
212 "linux-x64": "g1t-runner-linux-x64",
213 "linux-arm64": "g1t-runner-linux-arm64",
214 "macos-arm64": "g1t-runner-macos-arm64",
215 "macos-x64": "g1t-runner-macos-x64",
216 "windows-x64": "g1t-runner-windows-x64.exe",
217};