2323 * STOP execution, but report `ok: false` with no `error` — for cases the
2424 * parent wants to present gently (its own Callout) rather than as a red
2525 * failure row, while still skipping any success-only output.
26+ * Silent skips (`isSilentSkip = true`) remove the step's row from the UI
27+ * entirely and don't stop execution (`ok` is preserved) — for optional steps
28+ * whose absence is a non-event the user shouldn't see (e.g. an app with no
29+ * `setup.sh` to run).
2630 */
2731
2832import { useState , useEffect , useRef } from "react" ;
@@ -46,7 +50,7 @@ export interface Step {
4650 keepLogOnSuccess ?: boolean ;
4751}
4852
49- type StepStatus = "pending" | "running" | "ok" | "failed" | "warning" ;
53+ type StepStatus = "pending" | "running" | "ok" | "failed" | "warning" | "skipped" ;
5054
5155interface StepState {
5256 name : string ;
@@ -144,7 +148,14 @@ export function StepRunner({ title, steps, onDone }: Props) {
144148 const isWarning = err instanceof Error && ( err as any ) . isWarning === true ;
145149 const haltAsWarning =
146150 err instanceof Error && ( err as any ) . haltAsWarning === true ;
151+ const isSilentSkip = err instanceof Error && ( err as any ) . isSilentSkip === true ;
147152
153+ if ( isSilentSkip ) {
154+ setStates ( ( prev ) =>
155+ prev . map ( ( s , j ) => ( j === i ? { ...s , status : "skipped" } : s ) ) ,
156+ ) ;
157+ continue ;
158+ }
148159 if ( haltAsWarning ) {
149160 setStates ( ( prev ) =>
150161 prev . map ( ( s , j ) =>
@@ -188,21 +199,26 @@ export function StepRunner({ title, steps, onDone }: Props) {
188199
189200 return (
190201 < Section title = { title } >
191- { states . map ( ( step ) => (
192- < Box key = { step . name } flexDirection = "column" >
193- < Row
194- mark = { toMark ( step . status ) }
195- label = { step . name }
196- value = { step . message }
197- tone = { step . status === "failed" ? "danger" : "muted" }
198- />
199- { step . retainedLog && step . retainedLog . length > 0 && (
200- < Box marginTop = { 1 } marginBottom = { 1 } >
201- < LogTail lines = { step . retainedLog } height = { step . retainedLog . length } />
202- </ Box >
203- ) }
204- </ Box >
205- ) ) }
202+ { states
203+ . filter ( ( step ) => step . status !== "skipped" )
204+ . map ( ( step ) => (
205+ < Box key = { step . name } flexDirection = "column" >
206+ < Row
207+ mark = { toMark ( step . status ) }
208+ label = { step . name }
209+ value = { step . message }
210+ tone = { step . status === "failed" ? "danger" : "muted" }
211+ />
212+ { step . retainedLog && step . retainedLog . length > 0 && (
213+ < Box marginTop = { 1 } marginBottom = { 1 } >
214+ < LogTail
215+ lines = { step . retainedLog }
216+ height = { step . retainedLog . length }
217+ />
218+ </ Box >
219+ ) }
220+ </ Box >
221+ ) ) }
206222 { running && liveOutput . length > 0 && (
207223 < Box marginTop = { 1 } >
208224 < LogTail lines = { liveOutput } height = { LIVE_LOG_LINES } />
0 commit comments