@lchase/kiln 0.10.0 → 0.11.0
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.
- package/assets/serve.css +190 -480
- package/assets/serve.js +72 -3
- package/dist/board-view.js +688 -0
- package/dist/board.js +0 -97
- package/dist/serve-page.js +384 -324
- package/dist/serve.js +183 -11
- package/package.json +3 -2
package/dist/board.js
CHANGED
|
@@ -1,102 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { scheduledRetry } from "./attention.js";
|
|
4
|
-
const FEATURE_STAGES = ["spec", "build", "review", "approve", "land", "pr-review"];
|
|
5
|
-
const CATALOG = [
|
|
6
|
-
{ id: "queued", label: "Queued", who: "waiting · deps", tone: "queued" },
|
|
7
|
-
{ id: "spec", label: "Spec", who: "spec-writer · opus" },
|
|
8
|
-
{ id: "build", label: "Build", who: "builder · opus" },
|
|
9
|
-
{ id: "review", label: "Review", who: "sec · ux · ui · code" },
|
|
10
|
-
{ id: "approve", label: "Approve", who: "approver · opus" },
|
|
11
|
-
{ id: "explore", label: "Explore", who: "investigator · opus" },
|
|
12
|
-
{ id: "land", label: "Land", who: "git commit" },
|
|
13
|
-
{ id: "pr-review", label: "PR review", who: "pr-sync" },
|
|
14
|
-
{ id: "done", label: "Done", who: "local", tone: "merged" },
|
|
15
|
-
{ id: "merged", label: "Merged", who: "pr", tone: "merged" },
|
|
16
|
-
{ id: "needs-human", label: "Needs human", who: "approve · retry", tone: "human" },
|
|
17
|
-
];
|
|
18
|
-
const STEP_STAGE = {
|
|
19
|
-
spec: "spec",
|
|
20
|
-
build: "build",
|
|
21
|
-
verify: "build",
|
|
22
|
-
security: "review",
|
|
23
|
-
ux: "review",
|
|
24
|
-
ui: "review",
|
|
25
|
-
code: "review",
|
|
26
|
-
approver: "approve",
|
|
27
|
-
approve: "needs-human",
|
|
28
|
-
land: "land",
|
|
29
|
-
explore: "explore",
|
|
30
|
-
};
|
|
31
|
-
const HUMAN_STATES = new Set(["needs-human", "failed", "dead", "invalid", "rejected"]);
|
|
32
|
-
/**
|
|
33
|
-
* Column for one job. Human gates and broken runs sit in Needs human.
|
|
34
|
-
* A failed job with an automatic retry still scheduled stays on the step
|
|
35
|
-
* its last run reached. `scheduledRetry` is that decision.
|
|
36
|
-
*/
|
|
37
|
-
export function stageOf(job) {
|
|
38
|
-
if (scheduledRetry(job))
|
|
39
|
-
return runStage(job);
|
|
40
|
-
if (HUMAN_STATES.has(job.state))
|
|
41
|
-
return "needs-human";
|
|
42
|
-
if (job.state === "in-review")
|
|
43
|
-
return "pr-review";
|
|
44
|
-
if (job.state === "done")
|
|
45
|
-
return job.prUrl || job.prNumber ? "merged" : "done";
|
|
46
|
-
const current = job.steps.find((step) => step.phase === "current" || step.phase === "failed");
|
|
47
|
-
if (job.state === "queued" || job.state === "blocked")
|
|
48
|
-
return "queued";
|
|
49
|
-
if (job.state === "approved") {
|
|
50
|
-
if (current && current.id !== "land" && current.id !== "approve" && STEP_STAGE[current.id])
|
|
51
|
-
return STEP_STAGE[current.id];
|
|
52
|
-
return "land";
|
|
53
|
-
}
|
|
54
|
-
if (current && STEP_STAGE[current.id])
|
|
55
|
-
return STEP_STAGE[current.id];
|
|
56
|
-
return runStage(job);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Stage of the last step the run actually reached.
|
|
60
|
-
* The approve gate's column is Needs human; a scheduled retry is not a gate,
|
|
61
|
-
* so that step stays on Approve. Spec or Explore when the run never started a step.
|
|
62
|
-
*/
|
|
63
|
-
function runStage(job) {
|
|
64
|
-
const last = [...job.steps].reverse().find((step) => step.phase === "current" || step.phase === "failed");
|
|
65
|
-
const stage = last ? STEP_STAGE[last.id] : undefined;
|
|
66
|
-
if (stage && stage !== "needs-human")
|
|
67
|
-
return stage;
|
|
68
|
-
if (stage === "needs-human") {
|
|
69
|
-
const earlier = [...job.steps].reverse().find((step) => {
|
|
70
|
-
const mapped = STEP_STAGE[step.id];
|
|
71
|
-
return step.phase === "done" && mapped !== undefined && mapped !== "needs-human";
|
|
72
|
-
});
|
|
73
|
-
if (earlier)
|
|
74
|
-
return STEP_STAGE[earlier.id] ?? "approve";
|
|
75
|
-
return "approve";
|
|
76
|
-
}
|
|
77
|
-
return job.workflow === "investigation" ? "explore" : "spec";
|
|
78
|
-
}
|
|
79
|
-
/** Stages to render. An empty kiln still shows the feature pipeline, collapsed. */
|
|
80
|
-
export function stagesFor(jobs) {
|
|
81
|
-
const workflows = new Set(jobs.map((job) => job.workflow));
|
|
82
|
-
const wanted = new Set();
|
|
83
|
-
if (jobs.length === 0 || workflows.has("feature") || [...workflows].some((name) => name !== "investigation")) {
|
|
84
|
-
for (const id of FEATURE_STAGES)
|
|
85
|
-
wanted.add(id);
|
|
86
|
-
}
|
|
87
|
-
if (workflows.has("investigation"))
|
|
88
|
-
wanted.add("explore");
|
|
89
|
-
wanted.add("queued");
|
|
90
|
-
wanted.add("needs-human");
|
|
91
|
-
const reached = new Set(jobs.map((job) => stageOf(job)));
|
|
92
|
-
if (reached.has("done") || !reached.has("merged"))
|
|
93
|
-
wanted.add("done");
|
|
94
|
-
if (reached.has("merged"))
|
|
95
|
-
wanted.add("merged");
|
|
96
|
-
for (const id of reached)
|
|
97
|
-
wanted.add(id);
|
|
98
|
-
return CATALOG.filter((stage) => wanted.has(stage.id));
|
|
99
|
-
}
|
|
100
3
|
const REVIEW_FILE = /^(security|ux|ui|code)(?:\.(\d+))?\.json$/;
|
|
101
4
|
const TEXT_LIMIT = 8_000;
|
|
102
5
|
export function readReviewRounds(runDir) {
|