Finish the wonderland: System told truthfully, in eight tabs instead of ten

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 23:31:52 -04:00
parent 9ffaf45a4d
commit be0e55214b
57 changed files with 5040 additions and 925 deletions
+215 -2
View File
@@ -27,13 +27,19 @@ Singleton {
property bool postRepairScanPending: false
readonly property bool actionable: root.status === "warning" || root.status === "error"
readonly property bool busy: scanProcess.running || repairProcess.running || root.postRepairScanPending
readonly property bool busy: scanProcess.running || repairProcess.running
|| singleCheckProcess.running || root.postRepairScanPending
readonly property string helperPath: Quickshell.env("PANAMA_HEALTH_HELPER")
|| Quickshell.shellDir + "/scripts/panama-doctor"
readonly property var statuses: ["ok", "warning", "error", "unconfigured"]
readonly property var groups: ["desktop-foundation", "input-media", "integrations", "panama-tools"]
readonly property var overallStatuses: ["healthy", "warning", "error"]
readonly property var settingsTargets: ["my-home", "datetime"]
// Every page a check's "open" action is allowed to send someone to. This
// list and the doctor's authored targets are one change, not two: a target
// the doctor emits but this does not accept fails validAction, and a single
// rejected action invalidates the WHOLE snapshot -- so half of the pair
// does not degrade the row, it blanks the page.
readonly property var settingsTargets: ["my-home", "datetime", "updates"]
readonly property var instructionTargets: ["ddc-permissions"]
Process {
@@ -113,6 +119,54 @@ Singleton {
}
}
Process {
id: singleCheckProcess
property string checkId: ""
property int baseGeneration: 0
property string outputText: ""
property int exitCode: -1
property bool exited: false
property bool streamFinished: false
property bool settled: false
stdout: StdioCollector {
onStreamFinished: {
singleCheckProcess.outputText = this.text;
singleCheckProcess.streamFinished = true;
root.settleSingleCheck();
}
}
onExited: (exitCode, exitStatus) => {
singleCheckProcess.exitCode = exitCode;
singleCheckProcess.exited = true;
root.settleSingleCheck();
}
}
// `tee` rather than a shell redirect: the path is a value, not a fragment
// of a command line, so nothing about it can be read as syntax.
Process {
id: saveProcess
property string payload: ""
property string targetPath: ""
stdinEnabled: true
stdout: StdioCollector {}
onStarted: {
saveProcess.write(saveProcess.payload);
saveProcess.stdinEnabled = false;
}
onExited: (exitCode, exitStatus) => {
root.lastSaveResult = exitCode === 0
? "Report saved to " + saveProcess.targetPath + "."
: "Could not save the health report.";
saveProcess.payload = "";
}
}
Process {
id: failureNotification
}
@@ -229,6 +283,11 @@ Singleton {
};
if (candidate.action !== undefined)
check.action = root.safeAction(candidate.action);
// Carried through rather than reconstructed: the page shows the exact
// command a repair will run before running it, and the helper is the
// only thing that knows what that is.
if (candidate.repairCommand !== undefined)
check.repairCommand = candidate.repairCommand;
return check;
}
@@ -343,6 +402,154 @@ Singleton {
&& candidate.message.length > 0;
}
// ── Re-checking one row ─────────────────────────────────────────────────
//
// A full scan runs thirty probes. Asking again about the one row somebody
// just repaired should not cost the other twenty-nine, so the helper is
// asked for that check alone and the answer is spliced into the accepted
// snapshot. The reply arrives in the full snapshot shape, which means it
// goes through exactly the same validation as a whole scan -- an invalid
// single-check reply leaves the existing row alone rather than replacing a
// good answer with a bad one.
property string refreshingId: ""
readonly property bool refreshingCheck: singleCheckProcess.running
function refreshCheck(id: string): bool {
if (root.busy || singleCheckProcess.running)
return false;
if (!root.checks.some(candidate => candidate.id === id))
return false;
root.refreshingId = id;
singleCheckProcess.checkId = id;
singleCheckProcess.baseGeneration = root.acceptedGeneration;
singleCheckProcess.outputText = "";
singleCheckProcess.exitCode = -1;
singleCheckProcess.exited = false;
singleCheckProcess.streamFinished = false;
singleCheckProcess.settled = false;
singleCheckProcess.exec([root.helperPath, "check", id]);
return true;
}
function settleSingleCheck(): void {
if (singleCheckProcess.settled || !singleCheckProcess.exited
|| !singleCheckProcess.streamFinished)
return;
singleCheckProcess.settled = true;
root.finishSingleCheck(singleCheckProcess.exitCode, singleCheckProcess.checkId,
singleCheckProcess.baseGeneration,
singleCheckProcess.outputText);
}
function finishSingleCheck(exitCode: int, id: string, baseGeneration: int, text: string): bool {
root.refreshingId = "";
// A full scan that landed while this one row was being re-checked is
// the newer answer for every row including this one. Splicing a stale
// row back into it would undo part of a scan nobody asked to undo.
if (baseGeneration !== root.acceptedGeneration)
return false;
if (exitCode !== 0) {
root.lastError = "That check could not be re-run.";
return false;
}
let candidate;
try {
candidate = JSON.parse(text.trim());
} catch (error) {
root.lastError = "That check returned an unreadable response.";
return false;
}
if (!root.validSnapshot(candidate) || candidate.checks.length !== 1
|| candidate.checks[0].id !== id) {
root.lastError = "That check returned an invalid response.";
return false;
}
const replacement = root.safeCheck(candidate.checks[0]);
const merged = root.checks.map(check => check.id === id ? replacement : check);
root.checks = merged;
root.summary = root.countsFor(merged);
root.status = root.summary.status;
root.snapshot = Object.assign({}, root.snapshot, {
checks: merged,
summary: root.summary
});
root.lastError = "";
return true;
}
// The same arithmetic the helper does, applied to a list that has had one
// row replaced. Recomputed rather than left alone: a warning that repaired
// itself must leave the headline count, not just its own row.
function countsFor(checks: var): var {
const counts = { ok: 0, warning: 0, error: 0, unconfigured: 0 };
for (const check of checks)
counts[check.status] += 1;
return {
status: counts.error > 0 ? "error" : counts.warning > 0 ? "warning" : "healthy",
healthy: counts.ok,
warnings: counts.warning,
errors: counts.error,
unconfigured: counts.unconfigured
};
}
// ── Saving the report ───────────────────────────────────────────────────
property string lastSaveResult: ""
readonly property string defaultReportPath:
(Quickshell.env("HOME") ?? "") + "/panama-health-report.txt";
// Plain text rather than the JSON copyReport puts on the clipboard: a file
// somebody saves is a file somebody opens, and a report they can read
// without a JSON viewer is worth more than one that round-trips.
function reportText(): string {
const lines = [
"Panama system health",
"Generated " + String(root.snapshot?.generatedAt ?? "at an unknown time"),
"Status: " + root.status
+ " (" + root.summary.healthy + " ok, "
+ root.summary.warnings + " warnings, "
+ root.summary.errors + " errors, "
+ root.summary.unconfigured + " unconfigured)",
""
];
for (const version of root.snapshot?.context?.versions ?? [])
lines.push(version.id + ": " + version.version);
lines.push("");
for (const check of root.checks) {
lines.push("[" + check.status + "] " + check.title + " (" + check.id + ")");
lines.push(" " + check.detail);
if (check.repairCommand)
lines.push(" repair: " + check.repairCommand);
}
return lines.join("\n") + "\n";
}
function saveReport(path: string): bool {
if (saveProcess.running)
return false;
const target = path && path.length > 0 ? path : root.defaultReportPath;
if (!target || target.indexOf("/") !== 0) {
root.lastSaveResult = "That is not a path this can write to.";
return false;
}
root.lastSaveResult = "";
saveProcess.targetPath = target;
saveProcess.payload = root.reportText();
// Re-arm stdin: the previous run closed it, and a disabled channel
// stays closed even after being set back to true mid-run. Same
// discipline as copyProcess above.
saveProcess.stdinEnabled = true;
saveProcess.exec(["tee", target]);
return true;
}
function copyReport(): bool {
if (copyProcess.running)
return false;
@@ -366,7 +573,9 @@ Singleton {
generation: root.generation,
acceptedGeneration: root.acceptedGeneration,
repairingId: root.repairingId,
refreshingId: root.refreshingId,
lastRepair: root.lastRepair,
lastSaveResult: root.lastSaveResult,
lastError: root.lastError,
checks: root.checks.map(check => check.id),
checkStates: root.checks.map(check => ({ id: check.id, status: check.status }))
@@ -427,6 +636,10 @@ Singleton {
|| typeof candidate.title !== "string" || candidate.title.length === 0
|| typeof candidate.detail !== "string" || candidate.detail.length === 0)
return false;
if (candidate.repairCommand !== undefined
&& (typeof candidate.repairCommand !== "string"
|| candidate.repairCommand.length === 0))
return false;
return candidate.action === undefined || root.validAction(candidate.action);
}