@clemrig/factory 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +6 -17
  2. package/dist/app/doctor.d.ts +2 -4
  3. package/dist/app/doctor.js +6 -4
  4. package/dist/app/doctor.js.map +1 -1
  5. package/dist/app/factory.d.ts +2 -0
  6. package/dist/app/factory.js +13 -2
  7. package/dist/app/factory.js.map +1 -1
  8. package/dist/app/init.d.ts +1 -5
  9. package/dist/app/init.js +1 -13
  10. package/dist/app/init.js.map +1 -1
  11. package/dist/app/options.d.ts +17 -0
  12. package/dist/app/options.js +78 -0
  13. package/dist/app/options.js.map +1 -0
  14. package/dist/app/run.d.ts +4 -20
  15. package/dist/app/run.js +22 -93
  16. package/dist/app/run.js.map +1 -1
  17. package/dist/app/runs.d.ts +4 -32
  18. package/dist/app/runs.js +9 -61
  19. package/dist/app/runs.js.map +1 -1
  20. package/dist/cli/application.d.ts +1 -1
  21. package/dist/cli/application.js +1 -1
  22. package/dist/cli/args.js +2 -2
  23. package/dist/cli/args.js.map +1 -1
  24. package/dist/cli/doctor.d.ts +1 -1
  25. package/dist/cli/doctor.js +1 -1
  26. package/dist/cli/doctor.js.map +1 -1
  27. package/dist/cli/help.d.ts +1 -1
  28. package/dist/cli/help.js +1 -1
  29. package/dist/cli/init.d.ts +1 -1
  30. package/dist/cli/init.js +1 -1
  31. package/dist/cli/launcher.d.ts +1 -1
  32. package/dist/cli/launcher.js +4 -4
  33. package/dist/cli/launcher.js.map +1 -1
  34. package/dist/cli/reporter.d.ts +1 -1
  35. package/dist/cli/reporter.js +1 -2
  36. package/dist/cli/reporter.js.map +1 -1
  37. package/dist/cli/run.d.ts +1 -5
  38. package/dist/cli/run.js +24 -11
  39. package/dist/cli/run.js.map +1 -1
  40. package/dist/cli/ui.d.ts +1 -1
  41. package/dist/cli/ui.js +10 -3
  42. package/dist/cli/ui.js.map +1 -1
  43. package/dist/index.d.ts +3 -7
  44. package/dist/index.js +3 -5
  45. package/dist/index.js.map +1 -1
  46. package/dist/system/factory.d.ts +1 -1
  47. package/dist/system/factory.js +1 -1
  48. package/dist/system/factory.js.map +1 -1
  49. package/dist/system/npm.d.ts +5 -0
  50. package/dist/system/npm.js +14 -0
  51. package/dist/system/npm.js.map +1 -0
  52. package/dist/system/templates.d.ts +1 -1
  53. package/dist/system/templates.js +1 -1
  54. package/package.json +7 -17
  55. package/dist/engine/metrics.d.ts +0 -45
  56. package/dist/engine/metrics.js +0 -60
  57. package/dist/engine/metrics.js.map +0 -1
  58. package/dist/engine/primitives.d.ts +0 -34
  59. package/dist/engine/primitives.js +0 -81
  60. package/dist/engine/primitives.js.map +0 -1
  61. package/dist/engine/profiles.d.ts +0 -53
  62. package/dist/engine/profiles.js +0 -117
  63. package/dist/engine/profiles.js.map +0 -1
  64. package/dist/engine/runner.d.ts +0 -13
  65. package/dist/engine/runner.js +0 -157
  66. package/dist/engine/runner.js.map +0 -1
  67. package/dist/engine/types.d.ts +0 -194
  68. package/dist/engine/types.js +0 -2
  69. package/dist/engine/types.js.map +0 -1
  70. package/dist/engine/workflow.d.ts +0 -18
  71. package/dist/engine/workflow.js +0 -196
  72. package/dist/engine/workflow.js.map +0 -1
  73. package/dist/system/process.d.ts +0 -21
  74. package/dist/system/process.js +0 -238
  75. package/dist/system/process.js.map +0 -1
  76. package/dist/system/runtimes/adapter.d.ts +0 -90
  77. package/dist/system/runtimes/adapter.js +0 -20
  78. package/dist/system/runtimes/adapter.js.map +0 -1
  79. package/dist/system/runtimes/agent-runtime.d.ts +0 -45
  80. package/dist/system/runtimes/agent-runtime.js +0 -184
  81. package/dist/system/runtimes/agent-runtime.js.map +0 -1
  82. package/dist/system/runtimes/claude-code.d.ts +0 -10
  83. package/dist/system/runtimes/claude-code.js +0 -383
  84. package/dist/system/runtimes/claude-code.js.map +0 -1
  85. package/dist/system/runtimes/inspect.d.ts +0 -25
  86. package/dist/system/runtimes/inspect.js +0 -129
  87. package/dist/system/runtimes/inspect.js.map +0 -1
  88. package/dist/system/runtimes/pi.d.ts +0 -7
  89. package/dist/system/runtimes/pi.js +0 -235
  90. package/dist/system/runtimes/pi.js.map +0 -1
  91. package/dist/system/runtimes/protocol.d.ts +0 -9
  92. package/dist/system/runtimes/protocol.js +0 -38
  93. package/dist/system/runtimes/protocol.js.map +0 -1
  94. package/dist/system/runtimes/registry.d.ts +0 -5
  95. package/dist/system/runtimes/registry.js +0 -5
  96. package/dist/system/runtimes/registry.js.map +0 -1
  97. package/dist/system/store.d.ts +0 -20
  98. package/dist/system/store.js +0 -126
  99. package/dist/system/store.js.map +0 -1
  100. package/dist/ui/server.d.ts +0 -8
  101. package/dist/ui/server.js +0 -111
  102. package/dist/ui/server.js.map +0 -1
  103. package/dist/ui/static/dashboard.js +0 -266
  104. package/dist/ui/static/follow.js +0 -67
  105. package/dist/ui/static/index.html +0 -20
  106. package/dist/ui/static/style.css +0 -166
  107. package/dist/ui/static/timeline.js +0 -180
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/system/store.ts"],"names":[],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import { type Server } from "node:http";
2
- import type { Factory } from "../app/factory.js";
3
- /** A read-only view of the repository's runs on 127.0.0.1, on `port` or one chosen by the system. */
4
- export declare function startDashboard(factory: Factory, listen?: number): Promise<{
5
- url: string;
6
- server: Server;
7
- close(): Promise<void>;
8
- }>;
package/dist/ui/server.js DELETED
@@ -1,111 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { createServer, } from "node:http";
3
- import { basename } from "node:path";
4
- import { listRuns, loadRun, loadRunEvents, presentResult, retryMaximums, summarizeRun, UnknownRunError, } from "../app/runs.js";
5
- /** The runs, newest first; an unreadable run with its error. */
6
- async function runs(factory) {
7
- return {
8
- repository: basename(factory.dir),
9
- runs: (await listRuns(factory))
10
- .reverse()
11
- .map((entry) => ("state" in entry ? summarizeRun(entry.state) : entry)),
12
- };
13
- }
14
- /** A run with its events from the `after`-th: the page asks only for what it has not received. */
15
- async function detail(factory, id, after) {
16
- const state = await loadRun(factory, id);
17
- const events = await loadRunEvents(factory, id);
18
- const max = retryMaximums(factory, state.workflow);
19
- return {
20
- run: summarizeRun(state),
21
- runtimes: state.runtimes ?? {},
22
- error: state.error ?? null,
23
- events: events.slice(after),
24
- next: events.length,
25
- corrections: Object.entries(state.retries ?? {}).map(([key, count]) => ({
26
- key,
27
- count,
28
- max: max.get(key) ?? null,
29
- })),
30
- result: presentResult(factory, state),
31
- };
32
- }
33
- /** The page's files, served as they are: no script or style is ever inline. */
34
- const pageFiles = {
35
- "/": ["index.html", "text/html; charset=utf-8"],
36
- "/style.css": ["style.css", "text/css; charset=utf-8"],
37
- "/dashboard.js": ["dashboard.js", "text/javascript; charset=utf-8"],
38
- "/timeline.js": ["timeline.js", "text/javascript; charset=utf-8"],
39
- "/follow.js": ["follow.js", "text/javascript; charset=utf-8"],
40
- };
41
- async function loadPage() {
42
- const page = new Map();
43
- for (const [path, [file, type]] of Object.entries(pageFiles))
44
- page.set(path, {
45
- body: await readFile(new URL(`./static/${file}`, import.meta.url), "utf8"),
46
- type,
47
- });
48
- return page;
49
- }
50
- function send(response, status, body, type = "text/plain; charset=utf-8") {
51
- response.writeHead(status, {
52
- "content-type": type,
53
- "cache-control": "no-store",
54
- "x-content-type-options": "nosniff",
55
- "content-security-policy": "default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
56
- });
57
- response.end(body);
58
- }
59
- /** A read-only view of the repository's runs on 127.0.0.1, on `port` or one chosen by the system. */
60
- export async function startDashboard(factory, listen = 0) {
61
- let port = 0;
62
- const page = await loadPage();
63
- const handle = async (request, response) => {
64
- // Another Host means another site reached this port (DNS rebinding).
65
- if (request.headers.host !== `127.0.0.1:${port}` &&
66
- request.headers.host !== `localhost:${port}`)
67
- return send(response, 403, "Forbidden");
68
- if (request.method !== "GET")
69
- return send(response, 405, "Method Not Allowed");
70
- const url = new URL(request.url ?? "/", "http://127.0.0.1");
71
- const file = page.get(url.pathname);
72
- if (file)
73
- return send(response, 200, file.body, file.type);
74
- if (url.pathname === "/api/runs")
75
- return send(response, 200, JSON.stringify(await runs(factory)), "application/json");
76
- const id = /^\/api\/runs\/([^/]+)$/.exec(url.pathname)?.[1];
77
- if (id === undefined)
78
- return send(response, 404, "Not Found");
79
- const after = url.searchParams.get("after") ?? "0";
80
- if (!/^\d+$/.test(after))
81
- return send(response, 400, "Bad Request");
82
- let body;
83
- try {
84
- body = await detail(factory, decodeURIComponent(id), Number(after));
85
- }
86
- catch (error) {
87
- // A run that cannot be read now may be read at the next request.
88
- return error instanceof UnknownRunError
89
- ? send(response, 404, "Not Found")
90
- : send(response, 500, error instanceof Error ? error.message : String(error));
91
- }
92
- return send(response, 200, JSON.stringify(body), "application/json");
93
- };
94
- const server = createServer((request, response) => {
95
- handle(request, response).catch((error) => send(response, 500, error instanceof Error ? error.message : String(error)));
96
- });
97
- await new Promise((resolve, reject) => {
98
- server.once("error", reject);
99
- server.listen(listen, "127.0.0.1", () => resolve());
100
- });
101
- port = server.address().port;
102
- return {
103
- url: `http://127.0.0.1:${port}/`,
104
- server,
105
- close: () => new Promise((resolve, reject) => {
106
- server.close((error) => (error ? reject(error) : resolve()));
107
- server.closeAllConnections();
108
- }),
109
- };
110
- }
111
- //# sourceMappingURL=server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ui/server.ts"],"names":[],"mappings":"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"}
@@ -1,266 +0,0 @@
1
- // @ts-check
2
- /**
3
- * The dashboard: the run list every 2 seconds, and the selected run as
4
- * `follow.js` follows it. Text only, never HTML.
5
- */
6
- import { follower } from "./follow.js";
7
- import { cost, duration, timeline } from "./timeline.js";
8
-
9
- /** @typedef {import("../../engine/types.js").RunEvent} RunEvent */
10
- /** @typedef {import("./timeline.js").Block} Block */
11
-
12
- /**
13
- * @typedef {object} Summary
14
- * @property {string} id
15
- * @property {string} [workflow]
16
- * @property {string} [status]
17
- * @property {string} [stage]
18
- * @property {number | null} [durationMs]
19
- * @property {number | null} [costUsd]
20
- * @property {boolean} [partial]
21
- * @property {string} [updatedAt]
22
- * @property {string} [error] Why the run cannot be read.
23
- */
24
-
25
- /**
26
- * @typedef {object} Detail
27
- * @property {Required<Omit<Summary, "error">>} run
28
- * @property {Record<string, string>} runtimes
29
- * @property {string | null} error
30
- * @property {RunEvent[]} events
31
- * @property {number} next
32
- * @property {{ key: string; count: number; max: number | null }[]} corrections
33
- * @property {string[]} result
34
- */
35
-
36
- const LIST_EVERY_MS = 2000;
37
- const DETAIL_EVERY_MS = 1000;
38
-
39
- /**
40
- * @param {string} id
41
- * @returns {HTMLElement}
42
- */
43
- function byId(id) {
44
- const found = document.getElementById(id);
45
- if (!found) throw new Error(`Missing element #${id}`);
46
- return found;
47
- }
48
-
49
- /**
50
- * @param {string} tag
51
- * @param {string} [text]
52
- * @param {string} [className]
53
- * @returns {HTMLElement}
54
- */
55
- function el(tag, text, className) {
56
- const node = document.createElement(tag);
57
- if (text !== undefined) node.textContent = text;
58
- if (className) node.className = className;
59
- return node;
60
- }
61
-
62
- /** @param {string} iso */
63
- function time(iso) {
64
- const date = new Date(iso);
65
- return Number.isNaN(date.getTime())
66
- ? iso
67
- : date.toLocaleString(undefined, {
68
- dateStyle: "short",
69
- timeStyle: "medium",
70
- });
71
- }
72
-
73
- /** @param {import("../../engine/metrics.js").TokenCounts} tokens */
74
- function tokenLine(tokens) {
75
- return `${tokens.input} input · ${tokens.output} output · ${tokens.cacheRead} cache read · ${tokens.cacheWrite} cache write tokens`;
76
- }
77
-
78
- /**
79
- * @param {string} path
80
- * @returns {Promise<any>}
81
- */
82
- async function load(path) {
83
- const response = await fetch(path, { cache: "no-store" });
84
- if (!response.ok)
85
- throw Object.assign(
86
- new Error((await response.text()) || `HTTP ${response.status}`),
87
- { status: response.status },
88
- );
89
- return response.json();
90
- }
91
-
92
- /** The run the address names, or none when it cannot be read. */
93
- function fromHash() {
94
- try {
95
- return decodeURIComponent(location.hash.slice(1));
96
- } catch {
97
- return "";
98
- }
99
- }
100
-
101
- let selected = fromHash();
102
-
103
- /** @param {Summary[]} runs */
104
- function showRuns(runs) {
105
- byId("none").hidden = runs.length > 0;
106
- byId("runs").replaceChildren(
107
- ...runs.map((run) => {
108
- const row = el("tr");
109
- row.title = run.id;
110
- if (run.id === selected) row.className = "selected";
111
- if (run.error !== undefined) {
112
- const cause = el("td", run.error);
113
- cause.setAttribute("colspan", "4");
114
- row.append(el("td", run.id), el("td", "unreadable", "failed"), cause);
115
- } else
116
- row.append(
117
- el("td", run.workflow),
118
- el("td", run.status, run.status),
119
- el("td", run.stage),
120
- el("td", duration(run.durationMs ?? null)),
121
- el("td", cost(run.costUsd ?? null, run.partial ?? false)),
122
- el("td", time(run.updatedAt ?? "")),
123
- );
124
- row.addEventListener("click", () => select(run.id));
125
- return row;
126
- }),
127
- );
128
- }
129
-
130
- /** @param {Block} block */
131
- function showBlock(block) {
132
- const item = el("li", undefined, "block");
133
- const head = el("p");
134
- head.append(
135
- `${block.kind} ${block.stage} · `,
136
- el("span", block.status, block.status),
137
- block.durationMs === null ? "" : ` · ${duration(block.durationMs)}`,
138
- );
139
- item.append(head);
140
- const line = (/** @type {string} */ text, className = "line") =>
141
- item.append(el("p", text, className));
142
- const { call } = block;
143
- if (call?.model)
144
- line(`${call.runtime} ${call.model} · session ${call.session}`);
145
- for (const tool of block.tools)
146
- line(
147
- tool.status === "running"
148
- ? `${tool.name} …`
149
- : `${tool.name}${tool.status === "failed" ? " failed" : ""} ${((tool.durationMs ?? 0) / 1000).toFixed(1)} s`,
150
- );
151
- if (call?.usage)
152
- line(
153
- `${call.scope === "session" ? "Session total" : "Call"}: ${tokenLine(call.usage)} · ${cost(call.usage.costUsd, false)}`,
154
- );
155
- else if (block.tokens)
156
- line(
157
- `So far: ${tokenLine(block.tokens)}${block.provisional ? " (provisional)" : ""}`,
158
- );
159
- for (const warning of block.warnings) line(warning, "line warning");
160
- for (const entry of block.journal) line(`${time(entry.at)} ${entry.message}`);
161
- if (block.decision) {
162
- const { verdict, reason, destination } = block.decision;
163
- const retry = block.retry
164
- ? ` [${block.retry.key} ${block.retry.count}/${block.retry.max}]`
165
- : "";
166
- line(`${verdict} — ${reason} → ${destination ?? "end"}${retry}`);
167
- }
168
- if (block.detail) line(block.detail, "line failed");
169
- return item;
170
- }
171
-
172
- /**
173
- * @param {Detail} detail
174
- * @param {RunEvent[]} events Every event received for the run.
175
- */
176
- function showDetail(detail, events) {
177
- const { run } = detail;
178
- const summary = el("section");
179
- const line = el("p", undefined, "empty");
180
- line.append(
181
- el("span", run.status, run.status),
182
- ` · ${run.stage} · ${duration(run.durationMs)} · ${cost(run.costUsd, run.partial)}`,
183
- );
184
- summary.append(el("h3", `${run.workflow} · ${run.id}`), line);
185
- for (const runtime of Object.values(detail.runtimes))
186
- summary.append(el("p", runtime, "line"));
187
- if (detail.error) summary.append(el("pre", detail.error, "failed"));
188
- const stages = el("section");
189
- const blocks = el("ol");
190
- blocks.append(...timeline(events).map(showBlock));
191
- stages.append(el("h2", "Timeline"), blocks);
192
- const sections = [summary, stages];
193
- if (detail.corrections.length) {
194
- const corrections = el("section");
195
- corrections.append(el("h2", "Corrections"));
196
- for (const { key, count, max } of detail.corrections)
197
- corrections.append(el("p", `${key} ${count}/${max ?? "?"}`, "line"));
198
- sections.push(corrections);
199
- }
200
- const result = el("section");
201
- result.append(el("h2", "Result"), el("pre", detail.result.join("\n")));
202
- sections.push(result);
203
- byId("detail").replaceChildren(...sections);
204
- }
205
-
206
- /** @param {string} message */
207
- function updated(message) {
208
- byId("updated").textContent = message;
209
- }
210
-
211
- async function refreshRuns() {
212
- try {
213
- const { repository, runs } = await load("/api/runs");
214
- byId("repository").textContent = repository;
215
- showRuns(runs);
216
- updated(`Updated ${new Date().toLocaleTimeString()}`);
217
- } catch (error) {
218
- unavailable(error);
219
- }
220
- setTimeout(refreshRuns, LIST_EVERY_MS);
221
- }
222
-
223
- /** @param {unknown} error */
224
- const unavailable = (error) =>
225
- updated(
226
- `Unavailable: ${error instanceof Error ? error.message : String(error)}`,
227
- );
228
-
229
- /** @param {string} text */
230
- const placeholder = (text) =>
231
- byId("detail").replaceChildren(el("p", text, "empty"));
232
-
233
- const follow = follower({
234
- load,
235
- schedule: (work) => setTimeout(work, DETAIL_EVERY_MS),
236
- cancel: (timer) => clearTimeout(timer),
237
- show: (detail, events) => showDetail(detail, events),
238
- fail: (error) => {
239
- const { status } = /** @type {{ status?: number }} */ (error);
240
- // The follower stops on a run that does not exist and retries the rest.
241
- if (status === 404) placeholder("This run does not exist.");
242
- else if (status)
243
- placeholder(
244
- `This run cannot be read: ${error instanceof Error ? error.message : String(error)}`,
245
- );
246
- else unavailable(error);
247
- },
248
- });
249
-
250
- /** @param {string} id */
251
- function select(id) {
252
- if (id === selected) return;
253
- selected = id;
254
- if (fromHash() !== id) location.hash = encodeURIComponent(id);
255
- placeholder(id ? "Loading…" : "Select a run.");
256
- for (const row of byId("runs").children)
257
- row.className =
258
- /** @type {HTMLElement} */ (row).title === id ? "selected" : "";
259
- follow.select(id);
260
- }
261
-
262
- // A link or the history can change the selected run without reloading the page.
263
- window.addEventListener("hashchange", () => select(fromHash()));
264
- refreshRuns();
265
- if (selected) placeholder("Loading…");
266
- follow.select(selected);
@@ -1,67 +0,0 @@
1
- // @ts-check
2
- /**
3
- * Follows the selected run: asks only for the events not received yet, one
4
- * request after the answer to the previous one, drops an answer for a selection
5
- * that has changed since, and stops once the run has ended or does not exist.
6
- * Requests and timers are given, so that this logic is tested without a browser.
7
- */
8
-
9
- /** @typedef {import("../../engine/types.js").RunEvent} RunEvent */
10
-
11
- /**
12
- * @typedef {object} Answer
13
- * @property {{ status: string }} run
14
- * @property {RunEvent[]} events Events from the index the request asked for.
15
- * @property {number} next The index to ask for next.
16
- */
17
-
18
- /**
19
- * @template Timer
20
- * @param {object} options
21
- * @param {(path: string) => Promise<any>} options.load Rejects with `status` set on an HTTP error.
22
- * @param {(work: () => void) => Timer} options.schedule Runs `work` after the polling interval.
23
- * @param {(timer: Timer | undefined) => void} options.cancel
24
- * @param {(answer: any, events: RunEvent[]) => void} options.show The latest answer and every event received.
25
- * @param {(error: unknown) => void} options.fail
26
- */
27
- export function follower({ load, schedule, cancel, show, fail }) {
28
- /** One selection: a new object each time, so that an old answer never matches. */
29
- let current = { id: "", events: /** @type {RunEvent[]} */ ([]), next: 0 };
30
- /** @type {Timer | undefined} */
31
- let timer;
32
-
33
- /** @param {typeof current} target */
34
- async function refresh(target) {
35
- if (!target.id) return;
36
- /** @type {Answer} */
37
- let answer;
38
- try {
39
- answer = await load(
40
- `/api/runs/${encodeURIComponent(target.id)}?after=${target.next}`,
41
- );
42
- } catch (error) {
43
- if (target !== current) return;
44
- fail(error);
45
- // A run that does not exist will not appear later.
46
- const status = /** @type {{ status?: number }} */ (error).status;
47
- if (status !== 404) timer = schedule(() => refresh(target));
48
- return;
49
- }
50
- if (target !== current) return;
51
- target.events.push(...answer.events);
52
- target.next = answer.next;
53
- show(answer, target.events);
54
- if (answer.run.status === "running")
55
- timer = schedule(() => refresh(target));
56
- }
57
-
58
- return {
59
- /** @param {string} id */
60
- select(id) {
61
- if (id === current.id) return;
62
- cancel(timer);
63
- current = { id, events: [], next: 0 };
64
- refresh(current);
65
- },
66
- };
67
- }
@@ -1,20 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>factory</title>
7
- <link rel="stylesheet" href="/style.css">
8
- <script type="module" src="/dashboard.js"></script>
9
- </head>
10
- <body>
11
- <header><h1>factory</h1><span id="repository"></span><span id="updated"></span></header>
12
- <main>
13
- <div>
14
- <div class="table"><table><thead><tr><th>Workflow</th><th>Status</th><th>Stage</th><th>Duration</th><th>Cost</th><th>Updated</th></tr></thead><tbody id="runs"></tbody></table></div>
15
- <p id="none" class="empty" hidden>No run yet.</p>
16
- </div>
17
- <div id="detail"><p class="empty">Select a run.</p></div>
18
- </main>
19
- </body>
20
- </html>
@@ -1,166 +0,0 @@
1
- :root {
2
- color-scheme: light dark;
3
- --bg: #f7f7f5;
4
- --panel: #fff;
5
- --fg: #1d1d1b;
6
- --muted: #6f6e69;
7
- --line: #e4e3df;
8
- --accent: #2557d6;
9
- --ok: #19773a;
10
- --bad: #b42318;
11
- --run: #a15c07;
12
- }
13
- @media (prefers-color-scheme: dark) {
14
- :root {
15
- --bg: #111110;
16
- --panel: #1b1b19;
17
- --fg: #e8e7e3;
18
- --muted: #9b9a94;
19
- --line: #2c2c29;
20
- --accent: #7aa2ff;
21
- --ok: #5bd28a;
22
- --bad: #ff7a6b;
23
- --run: #f2b14c;
24
- }
25
- }
26
- * {
27
- box-sizing: border-box;
28
- }
29
- body {
30
- margin: 0;
31
- background: var(--bg);
32
- color: var(--fg);
33
- font:
34
- 14px / 1.45 ui-sans-serif,
35
- system-ui,
36
- -apple-system,
37
- sans-serif;
38
- }
39
- header {
40
- display: flex;
41
- flex-wrap: wrap;
42
- gap: 4px 12px;
43
- align-items: baseline;
44
- padding: 12px 16px;
45
- border-bottom: 1px solid var(--line);
46
- }
47
- header h1 {
48
- margin: 0;
49
- font-size: 16px;
50
- }
51
- header span {
52
- color: var(--muted);
53
- font-size: 13px;
54
- }
55
- #updated {
56
- margin-left: auto;
57
- }
58
- main {
59
- display: grid;
60
- grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
61
- gap: 16px;
62
- padding: 16px;
63
- }
64
- @media (max-width: 900px) {
65
- main {
66
- grid-template-columns: minmax(0, 1fr);
67
- }
68
- }
69
- .table {
70
- overflow-x: auto;
71
- background: var(--panel);
72
- border: 1px solid var(--line);
73
- border-radius: 6px;
74
- }
75
- table {
76
- width: 100%;
77
- border-collapse: collapse;
78
- }
79
- th,
80
- td {
81
- padding: 7px 10px;
82
- border-bottom: 1px solid var(--line);
83
- text-align: left;
84
- white-space: nowrap;
85
- }
86
- th {
87
- color: var(--muted);
88
- font-size: 12px;
89
- font-weight: 500;
90
- }
91
- tbody tr {
92
- cursor: pointer;
93
- }
94
- tbody tr:hover,
95
- tbody tr.selected {
96
- background: color-mix(in srgb, var(--accent) 12%, transparent);
97
- }
98
- .completed,
99
- .passed {
100
- color: var(--ok);
101
- }
102
- .failed {
103
- color: var(--bad);
104
- }
105
- .running {
106
- color: var(--run);
107
- }
108
- section {
109
- margin-bottom: 12px;
110
- padding: 10px 12px;
111
- background: var(--panel);
112
- border: 1px solid var(--line);
113
- border-radius: 6px;
114
- }
115
- h2 {
116
- margin: 0 0 8px;
117
- color: var(--muted);
118
- font-size: 12px;
119
- font-weight: 600;
120
- letter-spacing: 0.04em;
121
- text-transform: uppercase;
122
- }
123
- h3 {
124
- margin: 0 0 4px;
125
- font-size: 14px;
126
- overflow-wrap: anywhere;
127
- }
128
- ol {
129
- margin: 0;
130
- padding: 0;
131
- list-style: none;
132
- }
133
- .block {
134
- padding: 6px 0;
135
- border-bottom: 1px dotted var(--line);
136
- }
137
- .block:last-child {
138
- border-bottom: 0;
139
- }
140
- .block > p {
141
- margin: 0;
142
- }
143
- .line,
144
- pre {
145
- font:
146
- 12px / 1.45 ui-monospace,
147
- SFMono-Regular,
148
- Menlo,
149
- monospace;
150
- overflow-wrap: anywhere;
151
- }
152
- .line {
153
- margin: 2px 0 0 16px;
154
- color: var(--muted);
155
- }
156
- .warning {
157
- color: var(--run);
158
- }
159
- pre {
160
- margin: 0;
161
- white-space: pre-wrap;
162
- }
163
- .empty {
164
- margin: 0;
165
- color: var(--muted);
166
- }