Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
522 linesCodeBlameRaw

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.

The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.1// The Runner window's work: the runner on its own, live. What it is
2// doing, each kind of job and the job each is running, how jobs run and for
3// which workspace, its updates and its log, from the app's status
4// (src/runner/mod.rs View, in diagnosis.rs's words), and each change kept
5// the moment it is made. Everything it asks is a command in src/bridge.rs.
6(function () {
7 function byId(id) {
8 return document.getElementById(id);
9 }
10
11 function invoke(command, args) {
12 var core = window.__TAURI__ && window.__TAURI__.core;
13 if (core && typeof core.invoke === "function") return core.invoke(command, args || {});
14 return Promise.reject(new Error("This page belongs inside the g1t desktop app."));
15 }
16
17 function fail(error) {
18 var box = byId("error");
19 box.textContent = typeof error === "string" ? error : (error && error.message) || "That could not be changed.";
20 box.hidden = false;
21 }
22
23 // What each way of running jobs can reach, said plainly (src/runner/backend.rs).
24 var BACKENDS = {
25 sandboxed: { text: "The runner and every job run in a sandbox of their own. Nothing a job does reaches this computer.", warn: false },
26 docker: {
27 text: "Each job runs in a container of its own, but the runner controls this computer's Docker, which can reach your files. Not a sandbox.",
28 warn: true,
29 },
30 host: {
31 text: "Jobs run directly on this computer, as you: they can read, change and delete anything your account can. For jobs that need this system itself, such as building a Windows installer.",
32 warn: true,
33 },
34 };
35 var current = null;
36
37 // ── The runner ──────────────────────────────────────────────────────
38 // Its diagnosis, from src/runner/diagnosis.rs, as the tray and the
39 // site's Runners page show it; its buttons are the fixes.
40 function option(value, text) {
41 var item = document.createElement("option");
42 item.value = value;
43 item.textContent = text;
44 return item;
45 }
46
Merge branch 'main' into rm-agents47 var busy = window.g1tBusy;
48
49 // The whole runner's status, as far as a button waits on it: a press is
50 // done when any of this changes (busy.js).
51 function runnerStatus(runner) {
52 var d = runner.diagnosis;
53 var update = d.update || {};
54 return JSON.stringify([d.code, d.tone, d.title, d.cause, runner.chip.label, runner.enabled, runner.paused, update.checking, update.checked_at, update.ready]);
55 }
56
57 // One kind of job's, with the whole runner's.
58 function kindStatus(kind, runner) {
59 return JSON.stringify([runnerStatus(runner), kind.state, kind.enabled, kind.tone, kind.title, kind.cause]);
60 }
61
62 // A fix's button. Choosing is done here, in this window; a copy says it
63 // was copied. One that changes the runner (the catalogue says which:
64 // `waits`) stays busy until the status that follows; one the catalogue
65 // asks about first (`confirm`) asks.
66 function actionButton(action, primary, key, status) {
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.67 var button = document.createElement("button");
68 button.type = "button";
69 button.textContent = action.label;
70 if (primary) button.className = "primary";
Merge branch 'main' into rm-agents71 key = key + ":" + action.id;
72 if (busy.pressed(key, status)) busy.start(button);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.73 button.addEventListener("click", function () {
74 if (action.id === "choose_workspace") return byId("runnerWorkspace").focus();
75 if (action.id === "choose_backend") return byId("runnerBackend").focus();
Merge branch 'main' into rm-agents76 if (action.confirm && !window.confirm(action.confirm)) return;
77 busy.run(button, key, status, !!action.waits, function () {
78 return invoke("runner_control", { action: action.id });
79 }, fail).then(function (done) {
80 if (!done || action.id.indexOf("copy_") !== 0) return;
81 button.textContent = "Copied";
82 setTimeout(function () {
83 button.textContent = action.label;
84 }, 2000);
85 });
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.86 });
87 return button;
88 }
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.89
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.90 function element(tag, className, text) {
91 var item = document.createElement(tag);
92 if (className) item.className = className;
93 if (text != null) item.textContent = text;
94 return item;
95 }
96
97 // The catalogue's sentences name commands in backticks: `wsl --install`.
98 // Said here as code, which can be selected and copied.
99 function prose(into, text) {
100 into.textContent = "";
101 String(text || "")
102 .split("`")
103 .forEach(function (part, at) {
104 if (!part) return;
105 into.appendChild(at % 2 ? element("code", null, part) : document.createTextNode(part));
106 });
107 return into;
108 }
109
110 // ── Each kind of job, a card of its own ───────────────────────────────
111 // Linux jobs and Windows jobs (macOS jobs once they are released): what
112 // each is doing, why one isn't running and its fix, and its own Start or
113 // Stop, which leaves the other as it is. The words are the app's
114 // (CapabilityLine in src/runner/diagnosis.rs); the card only lays them out.
115 var SVG = "http://www.w3.org/2000/svg";
116 // Plain line icons, 16px on a 24px grid: a terminal for Linux jobs, a
117 // window for Windows jobs, a laptop for macOS jobs.
118 var ICONS = {
119 linux: ["M4 5h16a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z", "M7 10l3 2.5L7 15", "M12.5 15h4"],
120 windows: ["M4 4h16a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z", "M3 9h18", "M6.5 6.5h.01", "M9 6.5h.01"],
121 macos: ["M5 6a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v9H5z", "M2.5 18.5h19", "M3.5 18.5L5 15h14l1.5 3.5"],
122 };
123 // How each runner keeps a job from this computer, said plainly.
124 var ISOLATION = { "nested-container": "A fresh container in the VM", vm: "A VM of its own", container: "A container of its own", host: "None" };
125 var BUSY = { busy: true, starting: true, downloading: true, updating: true };
126 var cards = {};
127
128 // A small arrow: the link goes out to g1t.
129 function outward() {
130 var svg = document.createElementNS(SVG, "svg");
131 svg.setAttribute("viewBox", "0 0 24 24");
132 svg.setAttribute("width", "11");
133 svg.setAttribute("height", "11");
134 svg.setAttribute("fill", "none");
135 svg.setAttribute("stroke", "currentColor");
136 svg.setAttribute("stroke-width", "2");
137 svg.setAttribute("stroke-linecap", "round");
138 svg.setAttribute("aria-hidden", "true");
139 var path = document.createElementNS(SVG, "path");
140 path.setAttribute("d", "M7 17L17 7M9 7h8v8");
141 svg.appendChild(path);
142 return svg;
143 }
144
145 function icon(id) {
146 var svg = document.createElementNS(SVG, "svg");
147 svg.setAttribute("viewBox", "0 0 24 24");
148 svg.setAttribute("width", "16");
149 svg.setAttribute("height", "16");
150 svg.setAttribute("fill", "none");
151 svg.setAttribute("stroke", "currentColor");
152 svg.setAttribute("stroke-width", "1.75");
153 svg.setAttribute("stroke-linecap", "round");
154 svg.setAttribute("stroke-linejoin", "round");
155 svg.setAttribute("aria-hidden", "true");
156 (ICONS[id] || ICONS.linux).forEach(function (d) {
157 var path = document.createElementNS(SVG, "path");
158 path.setAttribute("d", d);
159 svg.appendChild(path);
160 });
161 return svg;
162 }
163
164 // A card's parts, made once and filled in on every status.
165 function makeCard(kind) {
166 var card = element("article", "kind");
167 card.setAttribute("role", "listitem");
168 card.setAttribute("aria-labelledby", "kind-" + kind.id + "-title");
169 var head = element("header", "kind-head");
170 var badge = element("span", "kind-icon");
171 badge.appendChild(icon(kind.id));
172 var name = element("span", "kind-name");
173 var title = element("h3", null, kind.label);
174 title.id = "kind-" + kind.id + "-title";
175 name.appendChild(title);
176 var pill = element("span", "pill");
177 // Its state is said when it changes, as "Linux jobs: Waiting for jobs".
178 pill.setAttribute("role", "status");
179 pill.setAttribute("aria-live", "polite");
180 pill.setAttribute("aria-atomic", "true");
181 var said = element("span", "visually-hidden", kind.label + ": ");
182 pill.appendChild(said);
183 pill.appendChild(element("span", "pill-dot"));
184 pill.appendChild(element("span", "pill-text"));
185 name.appendChild(pill);
186 head.appendChild(badge);
187 head.appendChild(name);
188 card.appendChild(head);
189 card.appendChild(element("p", "kind-about"));
190 var body = element("div", "kind-body");
191 card.appendChild(body);
192 var details = element("dl", "kind-details");
193 card.appendChild(details);
194 var actions = element("div", "kind-actions");
195 card.appendChild(actions);
196 return { root: card, pill: pill, about: card.querySelector(".kind-about"), body: body, details: details, actions: actions, signature: "" };
197 }
198
199 // What it is running, with where to see it on g1t.
200 function jobRow(job) {
201 var row = element("div", "kind-job");
202 row.appendChild(element("span", "kind-job-label", job.kind === "agent" ? "Agent work" : "Running"));
203 var what = element("span", "kind-job-what");
204 if (job.link) {
205 var link = element("a", null, job.name);
206 link.href = job.link;
207 what.appendChild(link);
208 } else {
209 what.appendChild(element("strong", null, job.name));
210 }
211 if (job.repo) what.appendChild(element("span", "muted", " in " + job.repo));
212 row.appendChild(what);
213 return row;
214 }
215
216 function progressRow(kind) {
217 var row = element("div", "kind-progress");
218 var bar = element("div", "bar");
219 bar.setAttribute("role", "progressbar");
220 bar.setAttribute("aria-valuemin", "0");
221 bar.setAttribute("aria-valuemax", "100");
222 bar.setAttribute("aria-valuenow", String(kind.progress));
223 bar.setAttribute("aria-label", kind.label + ": the sandbox's image");
224 var fill = element("span");
225 fill.style.width = Math.max(2, Math.min(100, kind.progress)) + "%";
226 bar.appendChild(fill);
227 row.appendChild(bar);
228 row.appendChild(element("span", "muted small", kind.progress + "%"));
229 return row;
230 }
231
232 function detail(list, term, value, given) {
233 if (!value) return;
234 var row = element("div");
235 row.appendChild(element("dt", null, term));
236 var dd = element("dd", null, given ? null : value);
237 if (given) dd.appendChild(given);
238 row.appendChild(dd);
239 list.appendChild(row);
240 }
241
Merge branch 'main' into rm-agents242 // Start or Stop for one kind of job, said for which: busy from the click
243 // until the status that follows says it started or stopped.
244 function toggleButton(kind, onFirst, runner) {
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.245 var on = kind.enabled;
246 var button = element("button", on ? "quiet" : onFirst ? "primary" : null);
247 button.type = "button";
Merge branch 'main' into rm-agents248 button.textContent = on ? "Stop" : "Start";
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.249 button.setAttribute("aria-label", (on ? "Stop " : "Start ") + kind.label);
Merge branch 'main' into rm-agents250 var key = "toggle:" + kind.id;
251 var status = kindStatus(kind, runner);
252 if (busy.pressed(key, status)) busy.start(button);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.253 button.addEventListener("click", function () {
Merge branch 'main' into rm-agents254 busy.run(button, key, status, true, function () {
255 return invoke("runner_control", { action: on ? "stop" : "start", capability: kind.id });
256 }, fail);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.257 });
258 return button;
259 }
260
261 function fillCard(card, kind, runner) {
262 var root = card.root;
263 root.dataset.state = kind.state;
264 root.dataset.tone = kind.tone;
265 root.classList.toggle("off", !kind.enabled);
266 card.pill.dataset.tone = kind.tone;
267 card.pill.classList.toggle("live", !!BUSY[kind.state]);
268 // Said again only when it changes, so a screen reader hears each change once.
269 var text = card.pill.querySelector(".pill-text");
270 if (text.textContent !== kind.title) text.textContent = kind.title;
271 if (card.about.textContent !== kind.about) card.about.textContent = kind.about;
272
273 // What changes the buttons and the words is drawn again only when it changes,
274 // so a button keeps its focus while the status ticks.
275 var update = runner.diagnosis.update || null;
Merge branch 'main' into rm-agents276 var signature = JSON.stringify([kind, runner.link, update && update.checked]);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.277 if (signature === card.signature) return;
278 card.signature = signature;
279
280 var body = card.body;
281 body.textContent = "";
282 if (kind.job) body.appendChild(jobRow(kind.job));
283 if (kind.state === "downloading" && kind.progress != null) body.appendChild(progressRow(kind));
284 if (kind.headline) body.appendChild(element("p", "kind-headline", kind.headline));
285 if (kind.cause) body.appendChild(prose(element("p", "kind-cause"), kind.cause));
286 if (kind.fix) body.appendChild(prose(element("p", "kind-fix"), kind.fix));
287 body.hidden = !body.firstChild;
288
289 var details = card.details;
290 details.textContent = "";
291 // Its name on g1t opens the workspace's Runners page, where it is listed.
292 var named = null;
293 if (kind.runner && runner.link) {
294 named = element("button", "link", kind.runner);
295 named.type = "button";
296 named.setAttribute("aria-label", "View " + kind.runner + " on g1t");
297 named.appendChild(outward());
298 named.addEventListener("click", function () {
299 invoke("runner_control", { action: "view_runners" }).catch(fail);
300 });
301 }
302 detail(details, "On g1t", kind.runner, named);
303 detail(details, "Version", kind.version ? "g1t-runner " + kind.version : null);
304 // A newer version waiting for this kind of job, and when g1t last looked.
305 if (update && (kind.update || kind.version)) {
306 var updates = element("span", "kind-update");
307 if (kind.update) updates.appendChild(element("span", "kind-update-ready", kind.update));
308 updates.appendChild(element("span", "muted", update.checked));
309 detail(details, "Updates", true, updates);
310 }
311 detail(details, "Isolation", ISOLATION[kind.isolation] || kind.isolation);
312 details.hidden = !details.firstChild;
313
314 var actions = card.actions;
315 actions.textContent = "";
316 // Its first fix stands out when it is the person's to do; while g1t
317 // sees to it (waiting for the release's images), none does.
318 var urgent = kind.tone === "problem" || kind.tone === "warning";
319 kind.actions.forEach(function (action, at) {
Merge branch 'main' into rm-agents320 actions.appendChild(actionButton(action, at === 0 && urgent && kind.state !== "waiting", kind.id, kindStatus(kind, runner)));
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.321 });
322 if (kind.can_toggle) {
Merge branch 'main' into rm-agents323 var toggle = toggleButton(kind, kind.actions.length === 0, runner);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.324 toggle.classList.add("end");
325 actions.appendChild(toggle);
326 }
327 actions.hidden = !actions.firstChild;
328 }
329
330 function renderKinds(runner) {
331 var list = byId("runner-kinds");
332 var kinds = (runner && runner.diagnosis.capabilities) || [];
333 list.hidden = kinds.length === 0;
334 var seen = {};
335 kinds.forEach(function (kind, at) {
336 seen[kind.id] = true;
337 var card = cards[kind.id] || (cards[kind.id] = makeCard(kind));
338 if (list.children[at] !== card.root) list.insertBefore(card.root, list.children[at] || null);
339 fillCard(card, kind, runner);
340 });
341 Object.keys(cards).forEach(function (id) {
342 if (seen[id]) return;
343 cards[id].root.remove();
344 delete cards[id];
345 });
346 list.classList.toggle("single", kinds.length === 1);
347 }
348
349 function renderRunner(runner) {
350 if (!runner) return;
351 var diagnosis = runner.diagnosis;
352 renderEngine(runner);
353 // The whole runner's line, when the cards don't already say it.
354 var cardsSayIt = diagnosis.in_capabilities && diagnosis.capabilities && diagnosis.capabilities.length > 0;
355 byId("runner-diagnosis").hidden = !!cardsSayIt;
356 byId("runner-dot").className = "dot " + diagnosis.tone;
357 byId("runner-title").textContent = diagnosis.title;
358 prose(byId("runner-cause"), diagnosis.cause);
359 prose(byId("runner-fix"), diagnosis.fix);
360 var actions = byId("runner-actions");
361 actions.textContent = "";
362 diagnosis.actions.forEach(function (action, at) {
Merge branch 'main' into rm-agents363 actions.appendChild(actionButton(action, at === 0, "runner", runnerStatus(runner)));
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.364 });
365 renderKinds(runner);
366 byId("runner").checked = !!runner.enabled;
367
368 var backend = byId("runnerBackend");
369 backend.value = runner.backend;
370 var about = BACKENDS[runner.backend] || BACKENDS.sandboxed;
371 byId("runner-backend-note").textContent = about.text;
372 byId("runner-backend-note").className = about.warn ? "warning-note" : "muted";
373
374 var workspaces = byId("runnerWorkspace");
375 workspaces.textContent = "";
376 var known = runner.workspaces.slice();
377 var listed = known.some(function (w) {
378 return w.slug === runner.workspace;
379 });
380 if (runner.workspace && !listed) known.unshift({ slug: runner.workspace, name: null });
381 known.forEach(function (w) {
382 workspaces.appendChild(option(w.slug, w.name ? w.name + " (" + w.slug + ")" : w.slug));
383 });
384 if (known.length === 0) workspaces.appendChild(option("", "Open g1t, signed in, to choose"));
385 workspaces.value = runner.workspace || "";
386 workspaces.disabled = known.length === 0;
387
388 byId("runner-machine").textContent = "This computer: " + runner.machine;
389 // The runner's version, when g1t last looked for a newer one, and, with
390 // no cards to say it, what becomes of one waiting.
391 var update = diagnosis.update;
392 var about = [runner.version ? "g1t-runner " + runner.version : null, update ? update.checked : null, update && update.note].filter(Boolean);
393 byId("runner-version").textContent = about.length ? about.join(" · ") : " ";
394 var check = byId("runner-check");
395 check.hidden = !update;
396 if (update) {
397 check.textContent = update.check.label;
Merge branch 'main' into rm-agents398 // Busy while the app looks, whoever asked, and from a click until it says it is looking.
399 if (update.checking || busy.pressed("check", runnerStatus(runner))) busy.start(check);
400 else busy.stop(check);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.401 }
Merge branch 'main' into rm-agents402 // A Start or Stop pressed is done once the status says so.
403 if (!busy.pressed("engine", runnerStatus(runner))) busy.stop(byId("engine-toggle"));
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.404 byId("runner-view").hidden = !runner.link;
405 // The log follows along, unless it was scrolled back to read.
406 var log = byId("runner-log");
407 var following = log.scrollTop + log.clientHeight >= log.scrollHeight - 8;
408 log.textContent = runner.log.length ? runner.log.join("\n") : "Nothing yet.";
409 if (following) log.scrollTop = log.scrollHeight;
410 }
411
412 byId("runnerBackend").addEventListener("change", save);
413 byId("runnerWorkspace").addEventListener("change", save);
Merge branch 'main' into rm-agents414 // A button that asks the runner for something: busy until the status
415 // that follows when it `waits`, or until the app has it.
416 function control(id, key, action, waits) {
417 var button = byId(id);
418 button.addEventListener("click", function () {
419 var status = current && current.runnerView ? runnerStatus(current.runnerView) : "";
420 busy.run(button, key, status, waits, function () {
421 return invoke("runner_control", { action: typeof action === "function" ? action() : action });
422 }, fail);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.423 });
Merge branch 'main' into rm-agents424 }
425 control("runner-view", "view", "view_runners", false);
426 control("runner-open-log", "log", "view_log", false);
427 // Looks now; what it finds installs as each kind of job is idle, and the status that follows says so.
428 control("runner-check", "check", "check_updates", true);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.429
430 // ── The whole runner, at the top ─────────────────────────────────────
431 // As the title bar's chip says it, with what it is doing in a line and
432 // its Start or Stop; the cards below say each kind of job.
433 function renderEngine(runner) {
434 byId("engine-dot").className = "dot " + runner.chip.tone;
435 var label = byId("engine-label");
436 if (label.textContent !== runner.chip.label) label.textContent = runner.chip.label;
437 var about = [runner.diagnosis.title, runner.version ? "g1t-runner " + runner.version : null, runner.workspace ? "for " + runner.workspace : null].filter(Boolean);
438 byId("engine-sub").textContent = about.join(" · ");
439 var toggle = byId("engine-toggle");
440 var on = runner.enabled && !runner.paused;
441 toggle.hidden = false;
442 toggle.textContent = on ? "Stop" : "Start";
443 toggle.className = on ? "quiet" : "primary";
444 toggle.dataset.action = on ? "stop" : "start";
445 }
446
Merge branch 'main' into rm-agents447 control("engine-toggle", "engine", function () {
448 return byId("engine-toggle").dataset.action;
449 }, true);
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.450
451 // Every setting, as the app has it now (the settings window changes the
452 // rest), with the runner's own as they are on the page.
453 var KEPT = ["startHidden", "closeToTray", "notifications", "flash", "badge", "systemTitleBar", "autoUpdate", "zoom", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"];
454 function save() {
455 invoke("get_settings")
456 .then(function (fresh) {
457 var settings = {};
458 KEPT.forEach(function (key) {
459 if (key in fresh) settings[key] = fresh[key];
460 });
461 settings.runner = byId("runner").checked;
462 settings.runnerBackend = byId("runnerBackend").value || "sandboxed";
463 settings.runnerWorkspace = byId("runnerWorkspace").value || null;
464 return invoke("save_settings", { settings: settings });
465 })
466 .then(
467 function (view) {
468 current = view;
469 renderRunner(view.runnerView);
470 },
471 function (error) {
472 fail(error);
473 if (current) renderRunner(current.runnerView);
474 },
475 );
476 }
477 byId("runner").addEventListener("change", save);
478
479 var events = window.__TAURI__ && window.__TAURI__.event;
480 if (events && typeof events.listen === "function") {
481 events
482 .listen("g1t-runner-status", function (event) {
483 if (current) current.runnerView = event.payload;
484 renderRunner(event.payload);
485 })
486 .catch(function () {});
487 }
488
489 // Links out, in the system's browser (src/bridge.js does the same on the site).
490 document.addEventListener("click", function (event) {
491 var anchor = event.target && event.target.closest ? event.target.closest("a[href]") : null;
492 if (!anchor) return;
493 event.preventDefault();
494 invoke("open_url", { url: anchor.href }).catch(function () {});
495 });
496
497 // g1t's own title bar, when the window has no system frame.
498 function frame(view) {
499 if (!view.customFrame) return;
500 if (view.platform === "macos") document.documentElement.classList.add("mac");
501 var bar = byId("titlebar");
502 bar.hidden = false;
503 document.body.classList.add("framed");
504 bar.addEventListener("mousedown", function (event) {
505 if (event.button !== 0 || event.target.closest("button")) return;
506 invoke("window_control", { action: "drag" }).catch(function () {});
507 });
508 byId("close-window").addEventListener("click", function () {
509 invoke("window_control", { action: "close" }).catch(function () {});
510 });
511 }
512
513 invoke("get_settings")
514 .then(function (view) {
515 current = view;
516 frame(view);
517 renderRunner(view.runnerView);
518 var log = byId("runner-log");
519 log.scrollTop = log.scrollHeight;
520 })
521 .catch(fail);
522})();

This file's history is long; its oldest lines are credited to the oldest commit read.