projection: begin the exact-path public epoch

The public tree and its history contain only the listed paths. Earlier projection history remains preserved internally.

Source-Sha: 913fde029b935671833254797f0f20f1eb9fabba

Policy-Sha: 913fde029b935671833254797f0f20f1eb9fabba

Tree-Digest: 180ae530c1058a2a5c89837bdce2d323ae83e669e38590ca72e75b8d92b7262f
This commit is contained in:
Fimeg 2026-09-08 21:59:33 -04:00
commit 67e26be2d9
838 changed files with 157302 additions and 0 deletions

36
desktop/qml/AppButton.qml Normal file
View file

@ -0,0 +1,36 @@
import QtQuick
import QtQuick.Controls.Basic
Button {
id: control
implicitHeight: Math.max(36, contentItem.implicitHeight + 16)
implicitWidth: contentItem.implicitWidth + 28
leftPadding: 14
rightPadding: 14
topPadding: 8
bottomPadding: 8
font.pixelSize: Theme.fontBody
background: Rectangle {
radius: Theme.radiusSm
color: control.down ? Theme.hover : control.hovered ? Theme.hover : Theme.raised
border.width: 1
border.color: control.activeFocus ? Theme.blue : Theme.bevelDark
opacity: control.enabled ? 1 : 0.5
Rectangle {
anchors { left: parent.left; right: parent.right; top: parent.top; margins: 1 }
height: 1
color: control.down ? Theme.bevelDark : Theme.bevelLight
}
}
contentItem: Text {
text: control.text
font: control.font
color: control.enabled ? Theme.text : Theme.faint
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}

View file

@ -0,0 +1,173 @@
import QtQuick
import QtQuick.Controls.Basic
import QtQuick.Layouts
Item {
id: root
property var events: []
property bool loading: false
property string query: ""
property var selected: ({})
signal refreshRequested()
readonly property var filtered: events.filter(e => {
if (!e) return false;
if (severity.currentIndex === 1 && e.severity !== "error" && e.severity !== "critical") return false;
if (severity.currentIndex === 2 && e.severity !== "warning") return false;
if (kind.currentIndex === 1 && e.event_type !== "agent_scan") return false;
if (kind.currentIndex === 2 && e.event_type !== "agent_install" && e.event_type !== "agent_update") return false;
return !query.length || JSON.stringify(e).toLowerCase().indexOf(query.toLowerCase()) >= 0;
})
function eventColor(e) {
return e.severity === "error" || e.severity === "critical" ? Theme.bad : e.severity === "warning" ? Theme.warn : e.event_subtype === "success" ? Theme.good : Theme.blue;
}
function stamp(e) { return e.created_at ? new Date(e.created_at).toLocaleString() : "Time not reported"; }
ColumnLayout {
anchors.fill: parent
anchors.margins: width < 760 ? 12 : 24
spacing: 12
PageHeader {
Layout.fillWidth: true
title: "History"
subtitle: "Scans, update outcomes, and machine events retained here after fleet synchronization. Latest 5,000 events."
AppButton { text: root.loading ? "Reading…" : "Refresh"; enabled: !root.loading; onClicked: root.refreshRequested() }
}
GridLayout {
Layout.fillWidth: true
columns: width < 720 ? 1 : 3
TextField {
id: search
Layout.fillWidth: true
placeholderText: "Find a package, operation, message, or reason"
color: Theme.text
placeholderTextColor: Theme.faint
selectByMouse: true
onTextChanged: debounce.restart()
background: Rectangle { color: Theme.surface; border.color: search.activeFocus ? Theme.blue : Theme.divider; radius: Theme.radiusSm }
Timer { id: debounce; interval: 180; onTriggered: root.query = search.text.trim() }
}
ComboBox { id: kind; model: ["All activity", "Scans", "Updates & installs"]; Layout.fillWidth: parent.columns === 1 }
ComboBox { id: severity; model: ["All outcomes", "Errors & critical", "Warnings"]; Layout.fillWidth: parent.columns === 1 }
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 28
color: Theme.titlebar
Text {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter; margins: 10 }
text: "ACTIVITY REGISTER " + root.filtered.length + " / " + root.events.length + " events"
color: "white"
font { family: Theme.mono; pixelSize: Theme.fontMeta; bold: true }
}
}
ListView {
id: list
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
model: root.filtered
spacing: 1
ScrollBar.vertical: ScrollBar {}
Text {
anchors.centerIn: parent
width: Math.min(parent.width - 32, 440)
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: root.loading ? "Reading local history…" : root.events.length ? "No events match these filters." : "No retained events yet. New scans and update outcomes will appear here."
visible: !list.count
color: Theme.dim
font.pixelSize: Theme.fontBody
}
delegate: ItemDelegate {
id: row
required property var modelData
width: list.width
implicitHeight: 78
onClicked: { root.selected = modelData; detail.open(); }
background: Rectangle { color: row.hovered || row.activeFocus ? Theme.selection : Theme.surface; border.color: row.activeFocus ? Theme.blue : "transparent" }
contentItem: RowLayout {
spacing: 12
Rectangle { width: 4; Layout.fillHeight: true; color: root.eventColor(row.modelData) }
ColumnLayout {
Layout.fillWidth: true
spacing: 4
Text {
Layout.fillWidth: true
text: row.modelData.message || row.modelData.event_type
textFormat: Text.PlainText
elide: Text.ElideRight
color: Theme.text
font.pixelSize: Theme.fontBody
}
Text {
Layout.fillWidth: true
text: root.stamp(row.modelData) + " · " + (row.modelData.component || "agent") + " · " + String(row.modelData.event_subtype || "event").replace(/_/g, " ")
elide: Text.ElideRight
color: Theme.dim
font.pixelSize: Theme.fontMeta
}
}
Text { text: "›"; color: Theme.blue; font.pixelSize: 22 }
}
}
}
}
Dialog {
id: detail
parent: Overlay.overlay
anchors.centerIn: parent
width: Math.min(parent.width - 32, 820)
height: Math.min(parent.height - 48, 640)
modal: true
title: "Event detail"
standardButtons: Dialog.Close
background: Rectangle { color: Theme.window; border.color: Theme.blue; border.width: 1; radius: Theme.radius }
contentItem: ScrollView {
clip: true
contentWidth: availableWidth
ColumnLayout {
width: detail.availableWidth
spacing: 12
Text {
Layout.fillWidth: true
text: root.stamp(root.selected) + " · " + String(root.selected.severity || "info").toUpperCase()
color: root.eventColor(root.selected)
wrapMode: Text.Wrap
font { pixelSize: Theme.fontMeta; bold: true }
}
TextArea {
Layout.fillWidth: true
text: root.selected.message || ""
textFormat: TextEdit.PlainText
readOnly: true
selectByMouse: true
wrapMode: TextEdit.Wrap
color: Theme.text
font.pixelSize: Theme.fontBody
background: Rectangle { color: Theme.surface; border.color: Theme.divider }
}
Text {
Layout.fillWidth: true
text: (root.selected.component || "agent") + " / " + (root.selected.event_type || "event") + " / " + (root.selected.event_subtype || "")
color: Theme.dim
wrapMode: Text.Wrap
font.pixelSize: Theme.fontMeta
}
Text { text: "RECORDED CONTEXT"; color: Theme.blue; font { pixelSize: Theme.fontMeta; bold: true; letterSpacing: 1 } }
TextArea {
Layout.fillWidth: true
text: JSON.stringify(root.selected.metadata || {}, null, 2)
textFormat: TextEdit.PlainText
readOnly: true
selectByMouse: true
wrapMode: TextEdit.Wrap
color: Theme.dim
font { family: Theme.mono; pixelSize: Theme.fontMeta }
background: Rectangle { color: Theme.surface; border.color: Theme.divider }
}
}
}
}
}

45
desktop/qml/LineGraph.qml Normal file
View file

@ -0,0 +1,45 @@
import QtQuick
Canvas {
id: root
property var values: []
property real ceiling: 100
property color lineColor: Theme.red
property color fillColor: Theme.tint(lineColor, 0.12)
property bool grid: true
onValuesChanged: requestPaint()
onWidthChanged: requestPaint()
onHeightChanged: requestPaint()
onCeilingChanged: requestPaint()
onPaint: {
const ctx = getContext("2d")
ctx.reset()
if (grid) {
ctx.strokeStyle = Theme.divider
ctx.lineWidth = 1
for (let y = 0; y <= 4; ++y) {
ctx.beginPath(); ctx.moveTo(0, y * height / 4); ctx.lineTo(width, y * height / 4); ctx.stroke()
}
}
if (!values || values.length < 2) return
const top = Math.max(1, ceiling)
const step = width / Math.max(1, values.length - 1)
ctx.beginPath()
for (let i = 0; i < values.length; ++i) {
const x = i * step
const y = height - Math.min(top, Math.max(0, Number(values[i]))) / top * height
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y)
}
ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.closePath()
ctx.fillStyle = fillColor; ctx.fill()
ctx.beginPath()
for (let j = 0; j < values.length; ++j) {
const x2 = j * step
const y2 = height - Math.min(top, Math.max(0, Number(values[j]))) / top * height
if (j === 0) ctx.moveTo(x2, y2); else ctx.lineTo(x2, y2)
}
ctx.strokeStyle = lineColor; ctx.lineWidth = 2; ctx.stroke()
}
}

4131
desktop/qml/Main.qml Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
import QtQuick
Rectangle {
required property string label
required property string value
property string detail: ""
property color accent: Theme.text
implicitWidth: 180
implicitHeight: 108
radius: Theme.radius
color: Theme.surface
border.width: 1
border.color: Theme.divider
Rectangle {
width: 3
height: 28
radius: 2
color: parent.accent
anchors.left: parent.left
anchors.leftMargin: 13
anchors.top: parent.top
anchors.topMargin: 16
}
Text {
text: parent.label.toUpperCase()
color: Theme.faint
font.pixelSize: Theme.fontMeta
font.letterSpacing: 1.1
anchors.left: parent.left
anchors.leftMargin: 26
anchors.top: parent.top
anchors.topMargin: 14
}
Text {
text: parent.value
color: parent.accent
font.pixelSize: 22
font.weight: 650
anchors.left: parent.left
anchors.leftMargin: 26
anchors.top: parent.top
anchors.topMargin: 36
}
Text {
text: parent.detail
color: Theme.dim
font.pixelSize: Theme.fontMeta
anchors.left: parent.left
anchors.leftMargin: 26
anchors.right: parent.right
anchors.rightMargin: 10
anchors.bottom: parent.bottom
anchors.bottomMargin: 11
elide: Text.ElideRight
}
}

55
desktop/qml/NavItem.qml Normal file
View file

@ -0,0 +1,55 @@
import QtQuick
Rectangle {
id: root
required property string label
property string badge: ""
property bool selected: false
signal clicked()
// A ColumnLayout allocates rows from implicitHeight. A plain Rectangle has
// none, so an explicit height laid out as a zero-high row and every entry
// drew on top of its neighbour.
implicitWidth: 180
implicitHeight: 38
radius: Theme.radiusSm
color: selected ? Theme.selection : mouse.containsMouse ? Theme.hover : "transparent"
Rectangle {
width: 3
height: 18
radius: 2
anchors.left: parent.left
anchors.leftMargin: 2
anchors.verticalCenter: parent.verticalCenter
color: root.selected ? Theme.blue : "transparent"
}
Text {
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
text: root.label
color: root.selected ? Theme.text : Theme.dim
font.pixelSize: Theme.fontBody
font.weight: root.selected ? 600 : 450
}
Rectangle {
visible: root.badge.length > 0
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
width: Math.max(20, badgeText.implicitWidth + 10)
height: 20
radius: 10
color: Theme.tint(root.selected ? Theme.red : Theme.faint, 0.22)
Text {
id: badgeText
anchors.centerIn: parent
text: root.badge
color: root.selected ? Theme.red : Theme.dim
font.pixelSize: 10
font.weight: 700
}
}
MouseArea { id: mouse; anchors.fill: parent; hoverEnabled: true; onClicked: root.clicked() }
}

View file

@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Layouts
GridLayout {
id: root
property string title
property string subtitle
default property alias actions: actionsRow.data
columns: width < 850 ? 1 : 2
columnSpacing: 20
rowSpacing: 12
ColumnLayout {
Layout.fillWidth: true
Layout.minimumWidth: 0
spacing: 6
Text {
Layout.fillWidth: true
text: root.title
color: Theme.text
font.pixelSize: Theme.fontTitle
font.weight: Font.Bold
wrapMode: Text.Wrap
}
Text {
Layout.fillWidth: true
text: root.subtitle
color: Theme.dim
font.pixelSize: Theme.fontBody
wrapMode: Text.Wrap
}
}
RowLayout {
id: actionsRow
Layout.fillWidth: root.columns === 1
Layout.maximumWidth: root.width
spacing: 8
}
}

92
desktop/qml/ScanPanel.qml Normal file
View file

@ -0,0 +1,92 @@
import QtQuick
import QtQuick.Controls.Basic
import QtQuick.Layouts
Rectangle {
id: root
property var snapshot: ({})
property bool running: false
readonly property var scanners: Object.keys(snapshot.scanners || {}).sort().map(key => snapshot.scanners[key])
implicitHeight: body.implicitHeight + 24
color: Theme.surface
border.color: Theme.divider
radius: Theme.radius
function stamp(value) {
return !value || String(value).indexOf("0001-") === 0 ? "Not scanned yet" : new Date(value).toLocaleString();
}
ColumnLayout {
id: body
anchors { left: parent.left; right: parent.right; top: parent.top; margins: 12 }
spacing: 8
RowLayout {
Layout.fillWidth: true
Rectangle { width: 7; height: 7; color: root.running ? Theme.warn : Theme.blue }
Text {
Layout.fillWidth: true
text: root.running ? "SCANNING THIS MACHINE" : "SCAN STATUS"
color: Theme.blue
font { pixelSize: Theme.fontMeta; bold: true; letterSpacing: 1 }
}
Text {
text: root.stamp(root.snapshot.last_scan_time)
color: Theme.dim
font.pixelSize: Theme.fontMeta
}
}
Text {
visible: !root.scanners.length
Layout.fillWidth: true
text: root.running ? "The Agent is checking available package sources." : "No scanner results yet. Run a scan to establish update coverage."
color: Theme.dim
wrapMode: Text.Wrap
font.pixelSize: Theme.fontBody
}
Repeater {
model: root.scanners
ColumnLayout {
required property var modelData
Layout.fillWidth: true
spacing: 3
RowLayout {
Layout.fillWidth: true
Text {
text: String(modelData.name).toUpperCase()
Layout.preferredWidth: 90
color: Theme.text
font { family: Theme.mono; pixelSize: Theme.fontMeta; bold: true }
}
Text {
Layout.fillWidth: true
text: modelData.status === "success" ? modelData.update_count + " available" : String(modelData.status || "unknown")
color: modelData.status === "success" ? Theme.good : Theme.warn
font.pixelSize: Theme.fontMeta
}
Text {
text: (Number(modelData.last_duration_ms || 0) / 1000).toFixed(1) + "s · " + root.stamp(modelData.last_scan_time)
color: Theme.faint
font.pixelSize: Theme.fontMeta
}
}
Text {
Layout.fillWidth: true
visible: Boolean(modelData.last_error)
text: modelData.last_error || ""
textFormat: Text.PlainText
color: Theme.bad
wrapMode: Text.Wrap
font.pixelSize: Theme.fontMeta
}
}
}
Text {
visible: root.scanners.some(s => s.status !== "success")
Layout.fillWidth: true
text: "A source did not complete. Its previous update observations may still be listed below."
color: Theme.warn
wrapMode: Text.Wrap
font.pixelSize: Theme.fontMeta
}
}
}

49
desktop/qml/Theme.qml Normal file
View file

@ -0,0 +1,49 @@
pragma Singleton
import QtQuick
QtObject {
property bool dark: true
readonly property color window: dark ? "#1b1d1e" : "#e5e5df"
readonly property color rail: dark ? "#181a1b" : "#ffffff"
readonly property color surface: dark ? "#181a1b" : "#ffffff"
readonly property color raised: dark ? "#252a2e" : "#efefe9"
readonly property color hover: dark ? "#2a2d2f" : "#eef2f6"
readonly property color divider: dark ? "#393d40" : "#dce1e7"
readonly property color text: dark ? "#e5e2dc" : "#171a1f"
readonly property color dim: dark ? "#b2aca2" : "#5f6874"
readonly property color faint: dark ? "#979084" : "#8a939e"
readonly property color red: "#ef2525"
readonly property color redDim: dark ? "#380b0b" : "#fee2e2"
readonly property color good: "#32bd74"
readonly property color warn: "#e5a936"
readonly property color bad: "#ef5350"
readonly property color blue: dark ? "#85add6" : "#336699"
readonly property color selection: dark ? "#23394b" : "#d9e6f2"
readonly property color titlebar: "#336699"
readonly property color bevelLight: dark ? "#465057" : "#ffffff"
readonly property color bevelDark: dark ? "#111517" : "#a4aaa9"
readonly property color purple: "#ad7aff"
readonly property color cyan: "#30b8c9"
readonly property int railWidth: 216
readonly property int headerHeight: 72
readonly property int radius: 3
readonly property int radiusSm: 2
readonly property int spacing: 14
readonly property int spacingSm: 8
readonly property int fontTitle: 23
readonly property int fontHeading: 17
readonly property int fontBody: 14
readonly property int fontMeta: 12
readonly property string mono: {
const wanted = ["JetBrainsMono NF", "Cascadia Mono", "Consolas", "Adwaita Mono", "DejaVu Sans Mono"]
const installed = Qt.fontFamilies()
for (let i = 0; i < wanted.length; ++i)
if (installed.indexOf(wanted[i]) >= 0) return wanted[i]
return "monospace"
}
function tint(color, alpha) { return Qt.rgba(color.r, color.g, color.b, alpha) }
function pressure(percent) { return percent >= 90 ? bad : percent >= 75 ? warn : good }
}