@@ -11426,6 +11426,157 @@ let updateEnsaidConfig = (model: model, msg: ensaidConfigMsg): (model, Tea_Cmd.t
1142611426 }
1142711427}
1142811428
11429+ let updateStapeln = (model : model , msg : stapelnMsg ): (model , Tea_Cmd .t <msg >) => {
11430+ let st = model .stapeln
11431+ switch msg {
11432+ | SetPipelineUrl (url ) => (
11433+ {... model , stapeln : {... st , pipelineUrl : url }},
11434+ Tea_Cmd .none ,
11435+ )
11436+ | Connect => (
11437+ {... model , stapeln : {... st , loading : true , error : None }},
11438+ StapelnCmd .connect (st .pipelineUrl , r => Stapeln (Connected (Result .isOk (r )))),
11439+ )
11440+ | Connected (ok ) => (
11441+ {... model , stapeln : {... st , connected : ok , loading : false , error : ok ? None : Some ("Connection failed" )}},
11442+ Tea_Cmd .none ,
11443+ )
11444+ | UpdateConstraint (key , value ) => {
11445+ // Simple constraint updates by key name. The detailed constraint editor
11446+ // lives in stapeln's own frontend; PanLL provides high-level overrides.
11447+ let c = st .constraints
11448+ let newConstraints = switch key {
11449+ | "maxImageSizeMb" =>
11450+ {... c , maxImageSizeMb : Int .fromString (value )-> Option .getOr (c .maxImageSizeMb )}
11451+ | "memoryLimitMb" =>
11452+ {... c , memoryLimitMb : Int .fromString (value )-> Option .getOr (c .memoryLimitMb )}
11453+ | "cpuLimit" =>
11454+ {... c , cpuLimit : Float .fromString (value )-> Option .getOr (c .cpuLimit )}
11455+ | "requireHealthcheck" =>
11456+ {... c , requireHealthcheck : value === "true" }
11457+ | "requireNonRoot" =>
11458+ {... c , requireNonRoot : value === "true" }
11459+ | _ => c
11460+ }
11461+ ({... model , stapeln : {... st , constraints : newConstraints }}, Tea_Cmd .none )
11462+ }
11463+ | RequestValidation => (
11464+ {... model , stapeln : {... st , loading : true }},
11465+ StapelnCmd .requestValidation (st .pipelineUrl , r => Stapeln (
11466+ switch r {
11467+ | Ok (json ) => {
11468+ // Parse validation summary from JSON response.
11469+ // For now, create a minimal summary — full parsing comes with
11470+ // the stapeln backend integration.
11471+ ignore (json )
11472+ ValidationReceived ({
11473+ passed : true ,
11474+ errorCount : 0 ,
11475+ warningCount : 0 ,
11476+ infoCount : 0 ,
11477+ findings : [],
11478+ scanTimestamp : Date .now (),
11479+ })
11480+ }
11481+ | Error (err ) => {
11482+ ignore (err )
11483+ ValidationReceived ({
11484+ passed : false ,
11485+ errorCount : 1 ,
11486+ warningCount : 0 ,
11487+ infoCount : 0 ,
11488+ findings : [{
11489+ id : "conn-err" ,
11490+ level : "error" ,
11491+ rule : "CONN" ,
11492+ message : "Could not reach validation endpoint" ,
11493+ line : None ,
11494+ autoFixAvailable : false ,
11495+ }],
11496+ scanTimestamp : Date .now (),
11497+ })
11498+ }
11499+ },
11500+ )),
11501+ )
11502+ | ValidationReceived (summary ) => (
11503+ {... model , stapeln : {... st , lastValidation : Some (summary ), loading : false }},
11504+ Tea_Cmd .none ,
11505+ )
11506+ | RequestGenerate (format ) => (
11507+ {... model , stapeln : {... st , loading : true }},
11508+ StapelnCmd .requestGenerate (st .pipelineUrl , format , r =>
11509+ switch r {
11510+ | Ok (content ) => Stapeln (GenerateReceived (content ))
11511+ | Error (err ) => Stapeln (GenerateReceived ("# Error: " ++ err ))
11512+ }
11513+ ),
11514+ )
11515+ | GenerateReceived (content ) => (
11516+ {... model , stapeln : {... st , generatedArtifact : Some (content ), loading : false }},
11517+ Tea_Cmd .none ,
11518+ )
11519+ | RefreshStatus => (
11520+ {... model , stapeln : {... st , loading : true }},
11521+ StapelnCmd .refreshStatus (st .pipelineUrl , r =>
11522+ switch r {
11523+ | Ok (json ) => {
11524+ // Parse pipeline status from JSON response.
11525+ // Minimal stub — full parsing comes with backend integration.
11526+ ignore (json )
11527+ Stapeln (StatusReceived ({
11528+ health : PipelineUnknown ,
11529+ nodeCount : 0 ,
11530+ connectionCount : 0 ,
11531+ validationPassing : false ,
11532+ suggestions : [],
11533+ securityPosture : {
11534+ score : 0.0 ,
11535+ slsaCompliant : false ,
11536+ sbomPresent : false ,
11537+ signatureValid : false ,
11538+ vulnerabilities : 0 ,
11539+ criticalVulns : 0 ,
11540+ },
11541+ dependencies : [],
11542+ lastUpdated : Date .now (),
11543+ }))
11544+ }
11545+ | Error (_ ) => Stapeln (StatusReceived ({
11546+ health : PipelineUnknown ,
11547+ nodeCount : 0 ,
11548+ connectionCount : 0 ,
11549+ validationPassing : false ,
11550+ suggestions : [],
11551+ securityPosture : {
11552+ score : 0.0 ,
11553+ slsaCompliant : false ,
11554+ sbomPresent : false ,
11555+ signatureValid : false ,
11556+ vulnerabilities : 0 ,
11557+ criticalVulns : 0 ,
11558+ },
11559+ dependencies : [],
11560+ lastUpdated : Date .now (),
11561+ }))
11562+ }
11563+ ),
11564+ )
11565+ | StatusReceived (status ) => (
11566+ {... model , stapeln : {... st , pipelineStatus : Some (status ), loading : false }},
11567+ Tea_Cmd .none ,
11568+ )
11569+ | SetActiveTab (tab ) => (
11570+ {... model , stapeln : {... st , activeTab : tab }},
11571+ Tea_Cmd .none ,
11572+ )
11573+ | DismissError => (
11574+ {... model , stapeln : {... st , error : None }},
11575+ Tea_Cmd .none ,
11576+ )
11577+ }
11578+ }
11579+
1142911580/// ORCHESTRATOR: The main entry point for state updates.
1143011581/// Routes each message to its domain-specific sub-updater, then applies
1143111582/// contractile evaluation as a post-processing cognitive governance step.
@@ -11498,6 +11649,7 @@ let update = (model: model, msg: msg): (model, Tea_Cmd.t<msg>) => {
1149811649 | AccessibilityCtrl (subMsg ) => updateAccessibility (model , subMsg )
1149911650 | Tiling (subMsg ) => updateTiling (model , subMsg )
1150011651 | FocusDimming (subMsg ) => updateFocusDimming (model , subMsg )
11652+ | Stapeln (subMsg ) => updateStapeln (model , subMsg )
1150111653 | EnsaidConfig (subMsg ) => updateEnsaidConfig (model , subMsg )
1150211654 | Bus (busMsg ) =>
1150311655 switch busMsg {
0 commit comments