import QtQuick import QtQuick.Controls import QtQuick.Layouts // What the engine is set to: where it runs, how it frames itself, when it // asks, whether it is planning. Everything here writes straight into the // engine's config (AgentCore), never into a copy the engine cannot see. // // The panel scrolls (a phone-sized window cannot show it all) and every // control keeps a finger-sized hit area. Rectangle { id: side property string workspace: "" property string provider: "" property string model: "" property string mode: "coding" property int approval: 1 // cst_approval_t property bool planMode: false property bool running: false property string status: "" property string todo: "" signal modeRequested(string mode) signal approvalRequested(int approval) signal planModeRequested(bool on) readonly property alias contentColumn: col color: Theme.surface border.width: 1 border.color: Theme.border implicitHeight: col.implicitHeight + Theme.pad * 2 // One selectable row of a segmented control. component Seg: Button { id: seg property bool current: false flat: true implicitHeight: Theme.segmentHeight padding: 0 background: Rectangle { radius: Theme.radiusSm color: seg.current ? Theme.accentDim : (seg.hovered ? Theme.surfaceAlt : "transparent") border.width: 1 border.color: seg.current ? Theme.accent : Theme.border } contentItem: Text { text: seg.text color: seg.current ? Theme.text : Theme.textDim font.pixelSize: Theme.smallSize horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Flickable { anchors.fill: parent contentWidth: width contentHeight: col.implicitHeight + Theme.pad * 2 clip: true boundsBehavior: Flickable.StopAtBounds ScrollBar.vertical: ScrollBar {} ColumnLayout { id: col x: Theme.pad y: Theme.pad width: parent.width - Theme.pad * 2 spacing: Theme.gapL // --- where --- ColumnLayout { Layout.fillWidth: true spacing: 4 RowLayout { spacing: Theme.gap Rectangle { width: 8; height: 8; radius: 4; color: Theme.accent } Text { text: "CST-agent" color: Theme.text font.pixelSize: Theme.bodySize font.bold: true } Item { Layout.fillWidth: true } Text { visible: side.running text: "turn running" color: Theme.warn font.pixelSize: Theme.smallSize } } Text { Layout.fillWidth: true text: side.workspace.length ? side.workspace : "(no workspace)" color: Theme.textDim font.pixelSize: Theme.smallSize elide: Text.ElideMiddle ToolTip.visible: wsHover.hovered ToolTip.text: side.workspace HoverHandler { id: wsHover } } Text { Layout.fillWidth: true visible: side.provider.length > 0 || side.model.length > 0 text: (side.provider.length ? side.provider : "?") + (side.model.length ? " · " + side.model : "") color: Theme.textFaint font.pixelSize: Theme.smallSize elide: Text.ElideRight } Text { Layout.fillWidth: true visible: side.status.length > 0 text: side.status color: Theme.textFaint font.pixelSize: Theme.smallSize elide: Text.ElideRight } } // --- how it frames itself --- ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Mode"; color: Theme.textDim; font.pixelSize: Theme.smallSize; font.bold: true } RowLayout { Layout.fillWidth: true spacing: 4 Seg { objectName: "modeCoding" Layout.fillWidth: true text: "coding" current: side.mode !== "general" onClicked: side.modeRequested("coding") } Seg { objectName: "modeGeneral" Layout.fillWidth: true text: "general" current: side.mode === "general" onClicked: side.modeRequested("general") } } Text { Layout.fillWidth: true text: side.mode === "general" ? "documents, data, everyday files" : "code framed: repos, builds, tests" color: Theme.textFaint font.pixelSize: Theme.smallSize wrapMode: Text.Wrap } } // --- when it asks --- ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Approval"; color: Theme.textDim; font.pixelSize: Theme.smallSize; font.bold: true } RowLayout { Layout.fillWidth: true spacing: 4 Seg { Layout.fillWidth: true text: "ask" current: side.approval === 0 onClicked: side.approvalRequested(0) } Seg { Layout.fillWidth: true text: "auto" current: side.approval === 1 onClicked: side.approvalRequested(1) } Seg { Layout.fillWidth: true text: "yolo" current: side.approval === 2 onClicked: side.approvalRequested(2) } } Text { Layout.fillWidth: true text: side.approval === 0 ? "every tool asks first" : side.approval === 2 ? "never asks — writes go through" : "sandbox and rules decide, asks on doubt" color: Theme.textFaint font.pixelSize: Theme.smallSize wrapMode: Text.Wrap } RowLayout { Layout.fillWidth: true Layout.topMargin: 2 spacing: Theme.gap Switch { id: planSwitch objectName: "planSwitch" checked: side.planMode implicitHeight: Theme.touchTarget onClicked: side.planModeRequested(checked) } Text { text: "Plan mode" color: Theme.textDim font.pixelSize: Theme.smallSize } Item { Layout.fillWidth: true } } Text { Layout.fillWidth: true visible: side.planMode text: "read-only tools and a planning note" color: Theme.textFaint font.pixelSize: Theme.smallSize wrapMode: Text.Wrap } } // --- the plan the engine keeps --- TodoPanel { Layout.fillWidth: true text: side.todo } Text { Layout.fillWidth: true Layout.topMargin: Theme.gap text: "engine in-process · v" + Qt.application.version color: Theme.textFaint font.pixelSize: Theme.smallSize elide: Text.ElideRight } } } }