@codyswann/lisa 3.48.7 → 3.50.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/dist/cli/doctor-hook-copy-parity.d.ts +8 -0
- package/dist/cli/doctor-hook-copy-parity.d.ts.map +1 -0
- package/dist/cli/doctor-hook-copy-parity.js +121 -0
- package/dist/cli/doctor-hook-copy-parity.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +6 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/gate-report-agent-hooks.d.ts +40 -0
- package/dist/cli/gate-report-agent-hooks.d.ts.map +1 -0
- package/dist/cli/gate-report-agent-hooks.js +226 -0
- package/dist/cli/gate-report-agent-hooks.js.map +1 -0
- package/dist/cli/gate-report-assemble.d.ts +37 -0
- package/dist/cli/gate-report-assemble.d.ts.map +1 -0
- package/dist/cli/gate-report-assemble.js +69 -0
- package/dist/cli/gate-report-assemble.js.map +1 -0
- package/dist/cli/gate-report-cells.d.ts +27 -2
- package/dist/cli/gate-report-cells.d.ts.map +1 -1
- package/dist/cli/gate-report-cells.js +59 -14
- package/dist/cli/gate-report-cells.js.map +1 -1
- package/dist/cli/gate-report-contexts.d.ts +70 -0
- package/dist/cli/gate-report-contexts.d.ts.map +1 -0
- package/dist/cli/gate-report-contexts.js +72 -0
- package/dist/cli/gate-report-contexts.js.map +1 -0
- package/dist/cli/gate-report-facade.d.ts +62 -0
- package/dist/cli/gate-report-facade.d.ts.map +1 -0
- package/dist/cli/gate-report-facade.js +224 -0
- package/dist/cli/gate-report-facade.js.map +1 -0
- package/dist/cli/gate-report-fragment.d.ts +11 -0
- package/dist/cli/gate-report-fragment.d.ts.map +1 -0
- package/dist/cli/gate-report-fragment.js +100 -0
- package/dist/cli/gate-report-fragment.js.map +1 -0
- package/dist/cli/gate-report-html.d.ts +47 -0
- package/dist/cli/gate-report-html.d.ts.map +1 -0
- package/dist/cli/gate-report-html.js +49 -0
- package/dist/cli/gate-report-html.js.map +1 -0
- package/dist/cli/gate-report-joins.d.ts +37 -0
- package/dist/cli/gate-report-joins.d.ts.map +1 -0
- package/dist/cli/gate-report-joins.js +104 -0
- package/dist/cli/gate-report-joins.js.map +1 -0
- package/dist/cli/gate-report-merge.d.ts +22 -0
- package/dist/cli/gate-report-merge.d.ts.map +1 -0
- package/dist/cli/gate-report-merge.js +79 -0
- package/dist/cli/gate-report-merge.js.map +1 -0
- package/dist/cli/gate-report-preview.d.ts +0 -18
- package/dist/cli/gate-report-preview.d.ts.map +1 -1
- package/dist/cli/gate-report-preview.js +35 -266
- package/dist/cli/gate-report-preview.js.map +1 -1
- package/dist/cli/gate-report-rows.d.ts +39 -0
- package/dist/cli/gate-report-rows.d.ts.map +1 -0
- package/dist/cli/gate-report-rows.js +209 -0
- package/dist/cli/gate-report-rows.js.map +1 -0
- package/dist/cli/gate-report-sections.d.ts +32 -0
- package/dist/cli/gate-report-sections.d.ts.map +1 -0
- package/dist/cli/gate-report-sections.js +164 -0
- package/dist/cli/gate-report-sections.js.map +1 -0
- package/dist/cli/gate-report-style.d.ts +19 -0
- package/dist/cli/gate-report-style.d.ts.map +1 -0
- package/dist/cli/gate-report-style.js +97 -0
- package/dist/cli/gate-report-style.js.map +1 -0
- package/dist/cli/gate-report-summary.d.ts.map +1 -1
- package/dist/cli/gate-report-summary.js +3 -0
- package/dist/cli/gate-report-summary.js.map +1 -1
- package/dist/cli/gate-report-types.d.ts +132 -1
- package/dist/cli/gate-report-types.d.ts.map +1 -1
- package/dist/cli/gate-report-types.js +1 -1
- package/dist/cli/gate-report-upstream.d.ts +70 -0
- package/dist/cli/gate-report-upstream.d.ts.map +1 -0
- package/dist/cli/gate-report-upstream.js +90 -0
- package/dist/cli/gate-report-upstream.js.map +1 -0
- package/dist/cli/gate-report.d.ts +2 -0
- package/dist/cli/gate-report.d.ts.map +1 -1
- package/dist/cli/gate-report.js +98 -140
- package/dist/cli/gate-report.js.map +1 -1
- package/dist/cli/ui-cmd.d.ts +4 -0
- package/dist/cli/ui-cmd.d.ts.map +1 -1
- package/dist/cli/ui-cmd.js +10 -2
- package/dist/cli/ui-cmd.js.map +1 -1
- package/dist/cli/ui-gate-report.d.ts +57 -0
- package/dist/cli/ui-gate-report.d.ts.map +1 -0
- package/dist/cli/ui-gate-report.js +95 -0
- package/dist/cli/ui-gate-report.js.map +1 -0
- package/dist/core/hook-copy-parity.d.ts +81 -0
- package/dist/core/hook-copy-parity.d.ts.map +1 -0
- package/dist/core/hook-copy-parity.js +111 -0
- package/dist/core/hook-copy-parity.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +28 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/ui/README.md +56 -3
- package/ui/index.html +52 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a merge is actually blocked on one gate.
|
|
3
|
+
*
|
|
4
|
+
* The emitter computed the per-cell half of this from the first day and the
|
|
5
|
+
* renderer discarded every byte of it, which left the report unable to surface
|
|
6
|
+
* the class of finding it was built to find: a check that is `required` at push
|
|
7
|
+
* and gates NOTHING at merge, so the cost is paid on every developer's machine
|
|
8
|
+
* while anyone pushing from a hookless path skips it and merges anyway.
|
|
9
|
+
*
|
|
10
|
+
* Three answers, and the middle one is the whole reason the column exists.
|
|
11
|
+
* A property proved inside a job named after a different gate still blocks the
|
|
12
|
+
* merge — but the red build then names a property that did not fail, and a
|
|
13
|
+
* column that collapsed that into "yes" could not show it.
|
|
14
|
+
*
|
|
15
|
+
* The third answer is derived, not assumed: a job whose shell runs this gate's
|
|
16
|
+
* task, under a name that is not this gate's, whose context the ruleset
|
|
17
|
+
* requires. Where the workflows cannot be read the answer is the upstream
|
|
18
|
+
* refusal rather than "no" — "not blocked" is a claim, and this run would not
|
|
19
|
+
* have looked.
|
|
20
|
+
* @module cli/gate-report-merge
|
|
21
|
+
*/
|
|
22
|
+
import { hookInvokesTask } from "./gate-report-executors.js";
|
|
23
|
+
import { TIER_THREE_UNKNOWABLE, } from "./gate-report-facade.js";
|
|
24
|
+
/**
|
|
25
|
+
* The first job that proves this task under a name that is not this gate's.
|
|
26
|
+
* @param inputs - Verdict inputs
|
|
27
|
+
* @param required - The live required contexts
|
|
28
|
+
* @returns The blocking context and job name, or null
|
|
29
|
+
*/
|
|
30
|
+
function underAnotherName(inputs, required) {
|
|
31
|
+
const { task, label, facade } = inputs;
|
|
32
|
+
if (task === null)
|
|
33
|
+
return null;
|
|
34
|
+
for (const site of facade.jobSites) {
|
|
35
|
+
if (site.name === label || !hookInvokesTask(site.shell, task))
|
|
36
|
+
continue;
|
|
37
|
+
const context = site.contexts.find(one => required.includes(one));
|
|
38
|
+
if (context !== undefined)
|
|
39
|
+
return { context, job: site.name };
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether a merge is blocked on one gate, and under whose name.
|
|
45
|
+
* @param inputs - Verdict inputs
|
|
46
|
+
* @returns The verdict, or the honest refusal to give one
|
|
47
|
+
*/
|
|
48
|
+
export function mergeVerdict(inputs) {
|
|
49
|
+
const { expectedContext, required, facade } = inputs;
|
|
50
|
+
if (required.state !== "verified")
|
|
51
|
+
return required;
|
|
52
|
+
if (expectedContext !== null && required.value.includes(expectedContext)) {
|
|
53
|
+
return {
|
|
54
|
+
state: "verified",
|
|
55
|
+
value: { verdict: "yes", context: expectedContext, underJob: null },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const other = underAnotherName(inputs, required.value);
|
|
59
|
+
if (other !== null) {
|
|
60
|
+
return {
|
|
61
|
+
state: "verified",
|
|
62
|
+
value: {
|
|
63
|
+
verdict: "yes-under-another-name",
|
|
64
|
+
context: other.context,
|
|
65
|
+
underJob: other.job,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// A consumer holds no copy of the workflow, so it cannot see whether one of
|
|
70
|
+
// Lisa's own jobs proves this property under a different job's name. "No"
|
|
71
|
+
// would be a claim this run did not check.
|
|
72
|
+
if (!facade.qualityYmlPresent)
|
|
73
|
+
return TIER_THREE_UNKNOWABLE;
|
|
74
|
+
return {
|
|
75
|
+
state: "verified",
|
|
76
|
+
value: { verdict: "no", context: null, underJob: null },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=gate-report-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-merge.js","sourceRoot":"","sources":["../../src/cli/gate-report-merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,qBAAqB,GAEtB,MAAM,yBAAyB,CAAC;AAiBjC;;;;;GAKG;AACH,SAAS,gBAAgB,CACvB,MAA0B,EAC1B,QAA2B;IAE3B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACvC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC;YAAE,SAAS;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,MAA0B;IAE1B,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACrD,IAAI,QAAQ,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC;IACnD,IAAI,eAAe,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QACzE,OAAO;YACL,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;SACpE,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE;gBACL,OAAO,EAAE,wBAAwB;gBACjC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,QAAQ,EAAE,KAAK,CAAC,GAAG;aACpB;SACF,CAAC;IACJ,CAAC;IACD,4EAA4E;IAC5E,0EAA0E;IAC1E,2CAA2C;IAC3C,IAAI,CAAC,MAAM,CAAC,iBAAiB;QAAE,OAAO,qBAAqB,CAAC;IAC5D,OAAO;QACL,KAAK,EAAE,UAAU;QACjB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;KACxD,CAAC;AACJ,CAAC"}
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render the gate report as a standalone HTML page.
|
|
3
|
-
*
|
|
4
|
-
* Deliberately NOT part of `ui/index.html`. That file is one 13,000-line
|
|
5
|
-
* document with no build step and a known hazard where concurrent edits merge
|
|
6
|
-
* badly, and where the report should finally live is an open question nobody
|
|
7
|
-
* has ruled on. A separate page sidesteps both: it is a viewing surface for a
|
|
8
|
-
* payload that already exists, not a decision about the console's structure.
|
|
9
|
-
*
|
|
10
|
-
* Pure and total — report in, string out, no I/O — so the same emitter output
|
|
11
|
-
* always produces the same bytes.
|
|
12
|
-
*
|
|
13
|
-
* The rendering rule that matters: `unknown` must never look like a pass. A
|
|
14
|
-
* cell this run could not determine is drawn in its own hatched, muted style
|
|
15
|
-
* with its own label, and the header counts it in a band of its own rather
|
|
16
|
-
* than folding it into a green total.
|
|
17
|
-
* @module cli/gate-report-preview
|
|
18
|
-
*/
|
|
19
1
|
import type { GateReport } from "./gate-report-types.js";
|
|
20
2
|
/**
|
|
21
3
|
* Render the whole page.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-report-preview.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-preview.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gate-report-preview.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-preview.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAuBzD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,GACnB,MAAM,CAWR"}
|
|
@@ -1,169 +1,39 @@
|
|
|
1
|
-
/** How each declaration state is written and coloured. */
|
|
2
|
-
const DECLARATION_LABELS = {
|
|
3
|
-
required: "must",
|
|
4
|
-
optional: "tells",
|
|
5
|
-
off: "off",
|
|
6
|
-
"not-declared": "not declared",
|
|
7
|
-
};
|
|
8
|
-
/** Escape text for HTML text nodes and attribute values. */
|
|
9
|
-
const ESCAPES = {
|
|
10
|
-
"&": "&",
|
|
11
|
-
"<": "<",
|
|
12
|
-
">": ">",
|
|
13
|
-
'"': """,
|
|
14
|
-
"'": "'",
|
|
15
|
-
};
|
|
16
1
|
/**
|
|
17
|
-
*
|
|
18
|
-
* @param value - Raw text
|
|
19
|
-
* @returns Escaped text
|
|
20
|
-
*/
|
|
21
|
-
function escapeHtml(value) {
|
|
22
|
-
return value.replace(/[&<>"']/g, character => ESCAPES[character] ?? character);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* The bucket chip for one cell, or the honest refusal to classify it.
|
|
26
|
-
* @param bucket - The cell's bucket finding
|
|
27
|
-
* @returns One chip of HTML
|
|
28
|
-
*/
|
|
29
|
-
function bucketChip(bucket) {
|
|
30
|
-
if (bucket.state === "not-applicable")
|
|
31
|
-
return "";
|
|
32
|
-
if (bucket.state === "unknown") {
|
|
33
|
-
return `<span class="chip unknown" title="${escapeHtml(bucket.message)}">not checked here</span>`;
|
|
34
|
-
}
|
|
35
|
-
const titles = {
|
|
36
|
-
A: "declared, and an executor resolves the declaration",
|
|
37
|
-
B: "an executor exists, but no declaration reaches it",
|
|
38
|
-
C: "a declaration exists that nothing can execute",
|
|
39
|
-
D: "neither declared nor executed",
|
|
40
|
-
};
|
|
41
|
-
return `<span class="chip b-${bucket.value}" title="${escapeHtml(titles[bucket.value] ?? "")}">${bucket.value}</span>`;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* One matrix cell.
|
|
45
|
-
* @param cell - The (gate, moment) pair
|
|
46
|
-
* @returns A table cell
|
|
47
|
-
*/
|
|
48
|
-
function momentCell(cell) {
|
|
49
|
-
if (!cell.legal) {
|
|
50
|
-
return '<td class="m illegal" title="the registry does not permit declaring this gate here"></td>';
|
|
51
|
-
}
|
|
52
|
-
const label = DECLARATION_LABELS[cell.declaration] ?? cell.declaration;
|
|
53
|
-
const state = cell.declaration === "not-declared" ? "undeclared" : cell.declaration;
|
|
54
|
-
return `<td class="m"><span class="state ${state}">${escapeHtml(label)}</span>${bucketChip(cell.bucket)}</td>`;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Whether `package.json` has the command, said in three states.
|
|
58
|
-
* @param cell - The cell carrying the command
|
|
59
|
-
* @returns One chip of HTML
|
|
60
|
-
*/
|
|
61
|
-
function commandChip(cell) {
|
|
62
|
-
if (cell.commandExists.state === "unknown") {
|
|
63
|
-
return '<span class="chip unknown">command not checked</span>';
|
|
64
|
-
}
|
|
65
|
-
if (cell.commandExists.state === "not-applicable")
|
|
66
|
-
return "";
|
|
67
|
-
return cell.commandExists.value
|
|
68
|
-
? '<span class="chip ok">script exists</span>'
|
|
69
|
-
: '<span class="chip bad">no such script</span>';
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* The first cell of a row that carries a resolved command, for the task column.
|
|
73
|
-
* @param row - One gate's row
|
|
74
|
-
* @returns The most informative cell, or undefined
|
|
75
|
-
*/
|
|
76
|
-
function representativeCell(row) {
|
|
77
|
-
return (row.moments.find(cell => cell.legal && cell.declaration !== "not-declared") ?? row.moments.find(cell => cell.legal));
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Legal moments the project's own axis has no column for.
|
|
2
|
+
* The gate report as a standalone HTML document.
|
|
81
3
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
? ""
|
|
93
|
-
: `<div class="offaxis">also legal at ${escapeHtml(families.join(", "))}</div>`;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* The cloud job a gate maps to, from the static table.
|
|
97
|
-
* @param job - The job id, or null when the table has no pair for this gate
|
|
98
|
-
* @returns One cell fragment
|
|
99
|
-
*/
|
|
100
|
-
function jobCell(job) {
|
|
101
|
-
return job === null
|
|
102
|
-
? '<span class="chip none">no job</span>'
|
|
103
|
-
: `<code>${escapeHtml(job)}</code>`;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* One gate row.
|
|
107
|
-
* @param row - The gate
|
|
108
|
-
* @param axis - The report's moment axis
|
|
109
|
-
* @returns A table row
|
|
110
|
-
*/
|
|
111
|
-
function gateRow(row, axis) {
|
|
112
|
-
const cell = representativeCell(row);
|
|
113
|
-
const task = cell?.task ?? row.defaultTask ?? "—";
|
|
114
|
-
return [
|
|
115
|
-
"<tr>",
|
|
116
|
-
`<td><span class="gid">${escapeHtml(row.id)}</span><span class="glabel">${escapeHtml(row.label)}</span>`,
|
|
117
|
-
offAxisMoments(row, axis),
|
|
118
|
-
"</td>",
|
|
119
|
-
`<td class="proves">${escapeHtml(row.summary)}</td>`,
|
|
120
|
-
`<td><code>${escapeHtml(task)}</code>${cell === undefined ? "" : commandChip(cell)}</td>`,
|
|
121
|
-
row.moments.map(momentCell).join(""),
|
|
122
|
-
`<td>${jobCell(row.qualityJob)}<div class="tier3">reads the declaration: not checkable here</div></td>`,
|
|
123
|
-
"</tr>",
|
|
124
|
-
].join("");
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The ruleset section — including the case where it was not read.
|
|
128
|
-
* @param report - The whole report
|
|
129
|
-
* @returns A section of HTML
|
|
4
|
+
* A thin wrapper around the fragment the console tab renders, and nothing
|
|
5
|
+
* more. The two surfaces cannot disagree because there is only one renderer:
|
|
6
|
+
* this file supplies a `<head>`, a page frame, and the console's colour tokens
|
|
7
|
+
* so the same scoped stylesheet has something to resolve against.
|
|
8
|
+
*
|
|
9
|
+
* It exists for the cases the tab cannot serve — a report written to a file, a
|
|
10
|
+
* report attached to a build — and not as a second place the report is
|
|
11
|
+
* decided. Where the report lives was an open question when the fragment was
|
|
12
|
+
* first written; it has been ruled on, and the answer is the console tab.
|
|
13
|
+
* @module cli/gate-report-preview
|
|
130
14
|
*/
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return `<p class="unknown-note">Branch protection was not read this run — <strong>${escapeHtml(report.ruleset.reason)}</strong>. ${escapeHtml(report.ruleset.message)} Nothing below claims a gate does or does not block a merge.</p>`;
|
|
134
|
-
}
|
|
135
|
-
const { matched, declaredNotRequired, requiredNotDeclared } = report.ruleset.value;
|
|
136
|
-
const list = (values) => values.length === 0
|
|
137
|
-
? "<li><em>none</em></li>"
|
|
138
|
-
: values
|
|
139
|
-
.map(value => `<li><code>${escapeHtml(value)}</code></li>`)
|
|
140
|
-
.join("");
|
|
141
|
-
return [
|
|
142
|
-
'<div class="cols">',
|
|
143
|
-
`<div><h3>Matched <span class="count">${matched.length}</span></h3><p>Declared <code>required</code>, and the ruleset requires it.</p><ul>${list(matched)}</ul></div>`,
|
|
144
|
-
`<div><h3>Declared, not required <span class="count">${declaredNotRequired.length}</span></h3><p>The settings file asks for it; the ruleset does not enforce it, so it blocks nothing.</p><ul>${list(declaredNotRequired)}</ul></div>`,
|
|
145
|
-
`<div class="sharp"><h3>Required, not declared <span class="count">${requiredNotDeclared.length}</span></h3><p>A merge is blocked on these, and <strong>no declaration governs them</strong>. Changing the settings file cannot turn them on, off, or into something else.</p><ul>${list(requiredNotDeclared)}</ul></div>`,
|
|
146
|
-
"</div>",
|
|
147
|
-
].join("");
|
|
148
|
-
}
|
|
15
|
+
import { renderGateReportFragment } from "./gate-report-fragment.js";
|
|
16
|
+
import { escapeHtml } from "./gate-report-html.js";
|
|
149
17
|
/**
|
|
150
|
-
* The
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
18
|
+
* The console's token names, given dark values.
|
|
19
|
+
*
|
|
20
|
+
* The fragment's stylesheet reads the console's tokens with fallbacks, so a
|
|
21
|
+
* standalone page only has to define the same names once. Duplicating the
|
|
22
|
+
* fragment's own rules here would be the second source of truth this split
|
|
23
|
+
* exists to avoid.
|
|
24
|
+
*/
|
|
25
|
+
const DOCUMENT_TOKENS = `
|
|
26
|
+
:root{--ink:#e6e9f2;--muted:#98a0b5;--faint:#6b7280;--surface:#161923;
|
|
27
|
+
--surface2:#1b2030;--line:#252a38;--accent:#58a6ff;
|
|
28
|
+
--good:#7ee787;--good-soft:#123021;--warn:#e3b341;--warn-soft:#3a2c12;
|
|
29
|
+
--crit:#ff9492;--crit-soft:#3a1616;
|
|
30
|
+
--mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace}
|
|
31
|
+
*{box-sizing:border-box}
|
|
32
|
+
body{margin:0;background:#0f1115;color:var(--ink);
|
|
33
|
+
font:15px/1.55 ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif}
|
|
34
|
+
.page{max-width:1500px;margin:0 auto;padding:32px 24px 72px}
|
|
35
|
+
h1{font-size:25px;margin:0 0 8px}
|
|
36
|
+
`;
|
|
167
37
|
/**
|
|
168
38
|
* Render the whole page.
|
|
169
39
|
* @param report - The emitter's output
|
|
@@ -171,116 +41,15 @@ function summarySection(report) {
|
|
|
171
41
|
* @returns A complete, self-contained HTML document
|
|
172
42
|
*/
|
|
173
43
|
export function renderGateReportPreview(report, projectLabel) {
|
|
174
|
-
const axis = report.momentAxis;
|
|
175
|
-
const head = axis
|
|
176
|
-
.map(moment => `<th class="m">${escapeHtml(moment)}</th>`)
|
|
177
|
-
.join("");
|
|
178
44
|
return `<!doctype html>
|
|
179
45
|
<html lang="en"><head><meta charset="utf-8">
|
|
180
46
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
181
47
|
<title>Gate report — ${escapeHtml(projectLabel)}</title>
|
|
182
|
-
<style>${
|
|
183
|
-
<div class="
|
|
184
|
-
<header>
|
|
48
|
+
<style>${DOCUMENT_TOKENS}</style></head><body>
|
|
49
|
+
<div class="page">
|
|
185
50
|
<h1>What this project's checks actually prove</h1>
|
|
186
|
-
|
|
187
|
-
${summarySection(report)}
|
|
188
|
-
</header>
|
|
189
|
-
|
|
190
|
-
<section>
|
|
191
|
-
<h2>Every check, and what governs it</h2>
|
|
192
|
-
<p class="lede">One row per check. One column per moment this project can declare a check at — there is no bare "deploy" column, because Lisa has no such moment: the deploy families take an environment suffix and only appear once a project names one.</p>
|
|
193
|
-
<div class="legend">
|
|
194
|
-
<span><span class="state required">must</span> declared required</span>
|
|
195
|
-
<span><span class="state optional">tells</span> declared optional</span>
|
|
196
|
-
<span><span class="state off">off</span> declared off — different from never declared</span>
|
|
197
|
-
<span><span class="state undeclared">not declared</span> the settings file never mentions it here</span>
|
|
198
|
-
<span><span class="chip b-A">A</span> declared, and something reads the declaration</span>
|
|
199
|
-
<span><span class="chip b-B">B</span> something runs it anyway; the settings file has no say</span>
|
|
200
|
-
<span><span class="chip b-C">C</span> declared, but nothing can run it</span>
|
|
201
|
-
<span><span class="chip unknown">not checked here</span> this run could not determine it — NOT a pass</span>
|
|
202
|
-
</div>
|
|
203
|
-
<div class="scroll"><table>
|
|
204
|
-
<thead><tr><th>Check</th><th>What a pass proves</th><th>Command</th>${head}<th>Cloud job</th></tr></thead>
|
|
205
|
-
<tbody>${report.gates.map(row => gateRow(row, axis)).join("")}</tbody>
|
|
206
|
-
</table></div>
|
|
207
|
-
</section>
|
|
208
|
-
|
|
209
|
-
<section>
|
|
210
|
-
<h2>What a merge is actually blocked on</h2>
|
|
211
|
-
<p class="lede">The contexts the settings file implies, beside the ones the repository's branch-protection rules really require. Nothing compares these two today, so they are only ever equal by hand.</p>
|
|
212
|
-
${rulesetSection(report)}
|
|
213
|
-
</section>
|
|
214
|
-
|
|
215
|
-
<footer>
|
|
216
|
-
<p>Report format v${String(report.version)} · registry read from the running Lisa package · runner <code>${escapeHtml(report.runner.state === "verified" ? report.runner.value : "unknown")}</code>${report.declarationProblems.length === 0 ? "" : ` · <strong>${String(report.declarationProblems.length)} declaration problem(s)</strong>: ${escapeHtml(report.declarationProblems.join("; "))}`}</p>
|
|
217
|
-
<p>Not rendered yet, and deliberately: the agent on-edit scripts, the table of cloud jobs that ignore the settings file, and any filtering.</p>
|
|
218
|
-
</footer>
|
|
51
|
+
${renderGateReportFragment(report, projectLabel)}
|
|
219
52
|
</div>
|
|
220
53
|
</body></html>`;
|
|
221
54
|
}
|
|
222
|
-
/** All styling, inlined so the file opens from disk with no server. */
|
|
223
|
-
const STYLE = `
|
|
224
|
-
:root{--bg:#0f1115;--panel:#161923;--line:#252a38;--ink:#e6e9f2;--dim:#98a0b5;
|
|
225
|
-
--ok:#3fb950;--warn:#d29922;--bad:#f85149;--unk:#6b7280;--acc:#58a6ff}
|
|
226
|
-
*{box-sizing:border-box}
|
|
227
|
-
body{margin:0;background:var(--bg);color:var(--ink);
|
|
228
|
-
font:15px/1.55 ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif}
|
|
229
|
-
.wrap{max-width:1500px;margin:0 auto;padding:32px 24px 72px}
|
|
230
|
-
h1{font-size:26px;margin:0 0 8px}
|
|
231
|
-
h2{font-size:19px;margin:40px 0 6px;padding-top:24px;border-top:1px solid var(--line)}
|
|
232
|
-
h3{font-size:14px;margin:0 0 4px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim)}
|
|
233
|
-
.sub,.lede{color:var(--dim);margin:0 0 16px;max-width:80ch}
|
|
234
|
-
.stats{display:flex;flex-wrap:wrap;gap:12px;margin:20px 0 12px}
|
|
235
|
-
.stat{background:var(--panel);border:1px solid var(--line);border-radius:10px;
|
|
236
|
-
padding:12px 16px;min-width:170px}
|
|
237
|
-
.stat b{display:block;font-size:28px;line-height:1.1}
|
|
238
|
-
.stat span{color:var(--dim);font-size:12.5px}
|
|
239
|
-
.denominator{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acc);
|
|
240
|
-
border-radius:8px;padding:12px 16px;margin:0;max-width:100ch}
|
|
241
|
-
.legend{display:flex;flex-wrap:wrap;gap:8px 18px;margin:14px 0;color:var(--dim);font-size:12.5px}
|
|
242
|
-
.legend>span{display:flex;align-items:center;gap:6px}
|
|
243
|
-
.scroll{overflow-x:auto;border:1px solid var(--line);border-radius:10px}
|
|
244
|
-
table{border-collapse:collapse;width:100%;font-size:13px;background:var(--panel)}
|
|
245
|
-
th,td{text-align:left;padding:9px 11px;border-bottom:1px solid var(--line);vertical-align:top}
|
|
246
|
-
th{position:sticky;top:0;background:#1b2030;font-size:11.5px;text-transform:uppercase;
|
|
247
|
-
letter-spacing:.05em;color:var(--dim);z-index:1}
|
|
248
|
-
th.m,td.m{text-align:center;white-space:nowrap}
|
|
249
|
-
td.illegal{background:repeating-linear-gradient(45deg,transparent,transparent 5px,#1b2030 5px,#1b2030 10px)}
|
|
250
|
-
tr:hover td{background:#1a1f2e}
|
|
251
|
-
.gid{display:block;font-family:ui-monospace,monospace;font-size:12px;color:var(--acc)}
|
|
252
|
-
.glabel{display:block;color:var(--dim);font-size:12px}
|
|
253
|
-
.offaxis{margin-top:4px;color:var(--unk);font-size:11px;font-style:italic}
|
|
254
|
-
.proves{color:var(--dim);max-width:34ch}
|
|
255
|
-
code{font-family:ui-monospace,monospace;font-size:12px;background:#10131c;
|
|
256
|
-
border:1px solid var(--line);border-radius:4px;padding:1px 5px}
|
|
257
|
-
.state{display:inline-block;font-size:11px;border-radius:5px;padding:2px 7px;font-weight:600}
|
|
258
|
-
.required{background:#1d3a24;color:#7ee787;border:1px solid #2ea04326}
|
|
259
|
-
.optional{background:#3a3117;color:#e3b341;border:1px solid #d2992226}
|
|
260
|
-
.off{background:#3a1d1d;color:#ff9492;border:1px solid #f8514926}
|
|
261
|
-
.undeclared{background:#1b2030;color:var(--unk);border:1px dashed #3a4157}
|
|
262
|
-
.chip{display:inline-block;margin-left:5px;font-size:10.5px;border-radius:4px;
|
|
263
|
-
padding:1px 5px;font-weight:600;vertical-align:1px}
|
|
264
|
-
.b-A{background:#123021;color:#7ee787}
|
|
265
|
-
.b-B{background:#3a2c12;color:#e3b341}
|
|
266
|
-
.b-C{background:#3a1616;color:#ff9492}
|
|
267
|
-
.b-D{background:#2a2a2a;color:#bbb}
|
|
268
|
-
.ok{background:#123021;color:#7ee787}
|
|
269
|
-
.bad{background:#3a1616;color:#ff9492}
|
|
270
|
-
.none{background:#1b2030;color:var(--unk)}
|
|
271
|
-
.unknown{background:repeating-linear-gradient(45deg,#22262f,#22262f 3px,#191d25 3px,#191d25 6px);
|
|
272
|
-
color:#9aa3b8;border:1px dashed #3f465c}
|
|
273
|
-
.tier3{margin-top:5px;font-size:11px;color:var(--unk);font-style:italic}
|
|
274
|
-
.unknown-note{background:repeating-linear-gradient(45deg,#22262f,#22262f 4px,#191d25 4px,#191d25 8px);
|
|
275
|
-
border:1px dashed #3f465c;border-radius:8px;padding:14px 16px;color:#c2c9db}
|
|
276
|
-
.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px}
|
|
277
|
-
.cols>div{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
|
|
278
|
-
.cols .sharp{border-color:#7d2b2b;background:#1e1618}
|
|
279
|
-
.cols p{color:var(--dim);font-size:12.5px;margin:0 0 8px}
|
|
280
|
-
.cols ul{margin:0;padding-left:18px}
|
|
281
|
-
.cols li{margin:3px 0;font-size:12.5px}
|
|
282
|
-
.count{float:right;color:var(--ink);font-size:13px}
|
|
283
|
-
footer{margin-top:44px;padding-top:18px;border-top:1px solid var(--line);
|
|
284
|
-
color:var(--unk);font-size:12.5px}
|
|
285
|
-
`;
|
|
286
55
|
//# sourceMappingURL=gate-report-preview.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-report-preview.js","sourceRoot":"","sources":["../../src/cli/gate-report-preview.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gate-report-preview.js","sourceRoot":"","sources":["../../src/cli/gate-report-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGnD;;;;;;;GAOG;AACH,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAkB,EAClB,YAAoB;IAEpB,OAAO;;;uBAGc,UAAU,CAAC,YAAY,CAAC;SACtC,eAAe;;;EAGtB,wBAAwB,CAAC,MAAM,EAAE,YAAY,CAAC;;eAEjC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Finding, GateMomentCell, GateReportRow, MergeVerdict } from "./gate-report-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* One matrix cell.
|
|
4
|
+
* @param cell - The (gate, moment) pair
|
|
5
|
+
* @returns A table cell
|
|
6
|
+
*/
|
|
7
|
+
export declare function momentCell(cell: GateMomentCell): string;
|
|
8
|
+
/**
|
|
9
|
+
* Whether `package.json` has the command, said in three states and never none.
|
|
10
|
+
* @param cell - The cell carrying the command
|
|
11
|
+
* @returns One chip of HTML
|
|
12
|
+
*/
|
|
13
|
+
export declare function commandChip(cell: GateMomentCell): string;
|
|
14
|
+
/**
|
|
15
|
+
* The first cell of a row that carries a resolved command.
|
|
16
|
+
* @param row - One gate's row
|
|
17
|
+
* @returns The most informative cell, or undefined
|
|
18
|
+
*/
|
|
19
|
+
export declare function representativeCell(row: GateReportRow): GateMomentCell | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The command column: Lisa's default on top, any override beneath it.
|
|
22
|
+
* @param row - One gate's row
|
|
23
|
+
* @returns A table cell
|
|
24
|
+
*/
|
|
25
|
+
export declare function commandCell(row: GateReportRow): string;
|
|
26
|
+
/**
|
|
27
|
+
* The merge column: yes, yes under another job's name, or no.
|
|
28
|
+
* @param merge - The row's merge finding
|
|
29
|
+
* @returns A table cell
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeCell(merge: Finding<MergeVerdict>): string;
|
|
32
|
+
/**
|
|
33
|
+
* One gate row.
|
|
34
|
+
* @param row - The gate
|
|
35
|
+
* @param axis - The report's moment axis
|
|
36
|
+
* @returns A table row
|
|
37
|
+
*/
|
|
38
|
+
export declare function gateRow(row: GateReportRow, axis: readonly string[]): string;
|
|
39
|
+
//# sourceMappingURL=gate-report-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-rows.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-rows.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,aAAa,EACb,YAAY,EAEb,MAAM,wBAAwB,CAAC;AA2ChC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAQvD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAUxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,aAAa,GACjB,cAAc,GAAG,SAAS,CAM5B;AAmBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAStD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,MAAM,CAY9D;AAqDD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAa3E"}
|