import QtQuick import qs.Commons import qs.Ui // SessionsStage.qml - Sessions are running. They will keep the old provider until they are restarted, and one mid-request can lose that turn outright, so this is a decision rather than a notification. // // One stage of the claude-mode panel. Panel.qml hands itself in as `panel` // and owns all the state and actions; this file only draws them. Column { id: stage required property var panel width: parent.width visible: stage.panel.stage === "confirm" && stage.panel.sessionInfo !== null spacing: Style.space(7) readonly property int total: stage.panel.sessionInfo ? Number(stage.panel.sessionInfo.count) : 0 readonly property int busyCount: stage.panel.sessionInfo ? Number(stage.panel.sessionInfo.busy) : 0 Text { width: parent.width text: parent.total === 1 ? "1 Claude session is running" : parent.total + " Claude sessions are running" color: Color.popups.text wrapMode: Text.WordWrap font.family: stage.panel.uiFont font.pixelSize: Style.space(13) font.bold: true } // Not "they will keep using the old provider". Their endpoint and model // ids are fixed at startup, but the key is re-fetched on a timer and // will resolve to the new mode, which the old endpoint refuses - so // they fail rather than carry on. Text { width: parent.width text: "They keep pointing at " + stage.panel.pTitle(stage.panel.mode) + ", but their key is " + "re-fetched on a timer and will switch under them. Worse, if one takes a " + "reply from the new provider first, that provider's message-id format " + "goes into its transcript and Anthropic will refuse to resume it at all." color: Color.muted wrapMode: Text.WordWrap lineHeight: 1.2 font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Text { width: parent.width visible: parent.busyCount > 0 text: parent.busyCount === 1 ? "One is working right now and will break mid-turn." : parent.busyCount + " are working right now and will break mid-turn." color: stage.panel.urgentColor wrapMode: Text.WordWrap font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Column { width: parent.width spacing: Style.space(1) Repeater { model: stage.panel.sessionInfo ? stage.panel.sessionInfo.sessions : [] Item { required property var modelData width: stage.width height: Style.space(17) Text { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter text: parent.modelData.tty color: Color.muted font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Text { anchors.left: parent.left anchors.leftMargin: Style.space(52) anchors.right: busyTag.left anchors.rightMargin: Style.space(6) anchors.verticalCenter: parent.verticalCenter text: parent.modelData.cwd color: Color.popups.text elide: Text.ElideLeft font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Text { id: busyTag anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter visible: parent.modelData.busy === true text: "working" color: stage.panel.urgentColor font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } } } } // Flow, not Row: these can total more than the card is wide, and a // Row lays them straight past its right edge instead of wrapping. Flow { width: parent.width spacing: Style.space(7) // Restart is the only option that ends with every session on the mode // the bar is now claiming, so it leads and it is the primary. PillButton { fontFamily: stage.panel.uiFont; label: "Switch and restart" primary: true onTriggered: stage.panel.applySwitch("restart") } PillButton { fontFamily: stage.panel.uiFont; label: "Switch and close"; onTriggered: stage.panel.applySwitch("stop") } PillButton { fontFamily: stage.panel.uiFont; label: "Switch only"; onTriggered: stage.panel.applySwitch("none") } PillButton { fontFamily: stage.panel.uiFont; label: "Cancel"; onTriggered: stage.panel.resetFlow() } } }