refactor: archive GUI clients; keep minimal TUI with hooks/API
ci / tcc-check (push) Successful in 1m8s
ci / linux (aarch64, 0) (push) Failing after 1h0m3s
ci / linux (x86, 1) (push) Failing after 1h0m3s
ci / linux (x86_64, 1) (push) Failing after 1h0m2s
ci / windows (push) Failing after 50s

Move Qt/Tauri/full Web SPA under archive/, ship hermit as CLI/TUI plus
libcstcore and cst-webui/1 HTTP+SSE (turn lifecycle hooks, capabilities).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WHC
2026-10-30 22:49:23 +08:00
co-authored by Cursor
parent ea38247161
commit 5538ed3412
184 changed files with 14098 additions and 1858 deletions
+106
View File
@@ -0,0 +1,106 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// One stored session in the sidebar: its name (a rename, else its first
// prompt), how much is in it and when it was last written, and a way to drop
// it. The open one is marked. A file of its own because the sidebar lists them
// through a Repeater -- an inline component would not see modelData there.
Rectangle {
id: srow
property var entry: null
readonly property bool open: entry !== null && entry.current === true
objectName: "sessionRow:" + (entry !== null ? entry.id : "")
implicitHeight: rowCol.implicitHeight + 8
radius: Theme.radiusSm
color: srow.open ? Theme.accentDim
: rowHover.hovered ? Theme.surfaceAlt : "transparent"
border.width: 1
border.color: srow.open ? Theme.accent : "transparent"
signal activated(string id)
signal removeRequested(string id)
// "3h ago"; the entries carry ms since the epoch.
function ago(ms) {
if (!ms)
return "never"
const s = Math.max(0, (Date.now() - ms) / 1000)
if (s < 60)
return "just now"
if (s < 3600)
return Math.floor(s / 60) + "m ago"
if (s < 86400)
return Math.floor(s / 3600) + "h ago"
return Math.floor(s / 86400) + "d ago"
}
HoverHandler { id: rowHover }
MouseArea {
anchors.fill: parent
onClicked: srow.activated(srow.entry.id)
}
RowLayout {
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: 4
}
spacing: 2
ColumnLayout {
id: rowCol
Layout.fillWidth: true
Layout.leftMargin: 4
spacing: 0
Text {
Layout.fillWidth: true
elide: Text.ElideRight
text: srow.entry !== null && srow.entry.title.length ? srow.entry.title
: srow.entry !== null && srow.entry.firstUser.length ? srow.entry.firstUser
: "(no prompt yet)"
color: srow.open ? Theme.accentText : Theme.textDim
font.pixelSize: Theme.smallSize
}
Text {
Layout.fillWidth: true
elide: Text.ElideRight
text: {
if (srow.entry === null)
return ""
const n = srow.entry.messages
const when = srow.ago(srow.entry.mtime)
return n > 0 ? n + (n === 1 ? " message · " : " messages · ") + when
: when
}
color: srow.open ? Theme.accentTextDim : Theme.textFaint
font.pixelSize: Theme.smallSize
}
}
ToolButton {
objectName: "sessionDelete:" + (srow.entry !== null ? srow.entry.id : "")
implicitWidth: 26
implicitHeight: 26
ToolTip.visible: hovered
ToolTip.text: "Delete this session and its transcript"
contentItem: ThemeIcon {
name: "edit-delete"
glyph: "×"
size: 14
color: parent.hovered ? Theme.err
: srow.open ? Theme.accentTextDim : Theme.textFaint
}
background: Rectangle {
radius: Theme.radiusSm
color: parent.hovered ? Theme.surfaceHi : "transparent"
}
onClicked: srow.removeRequested(srow.entry.id)
}
}
}