@@ -91,7 +91,7 @@ extension ExFigCommand {
9191 let ui = ExFigCommand . terminalUI!
9292
9393 // Discover and validate configs
94- let validConfigs = try discoverAndValidateConfigs ( ui: ui)
94+ let ( validConfigs, conflicts ) = try discoverAndValidateConfigs ( ui: ui)
9595 guard !validConfigs. isEmpty else { return }
9696
9797 // Prepare configs with checkpoint handling
@@ -111,6 +111,7 @@ extension ExFigCommand {
111111 // Execute batch
112112 let ( result, rateLimiter) = await executeBatch (
113113 configs: configs,
114+ conflicts: conflicts,
114115 checkpoint: checkpoint,
115116 workingDirectory: workingDirectory,
116117 ui: ui
@@ -127,11 +128,13 @@ extension ExFigCommand {
127128
128129 // MARK: - Run Helpers
129130
130- private func discoverAndValidateConfigs( ui: TerminalUI ) throws -> [ URL ] {
131+ private func discoverAndValidateConfigs(
132+ ui: TerminalUI
133+ ) throws -> ( configs: [ URL ] , conflicts: [ OutputPathConflict ] ) {
131134 let configURLs = try discoverConfigs ( ui: ui)
132135 guard !configURLs. isEmpty else {
133136 ui. warning ( . noConfigsFound)
134- return [ ]
137+ return ( [ ] , [ ] )
135138 }
136139
137140 let discovery = ConfigDiscovery ( )
@@ -144,17 +147,11 @@ extension ExFigCommand {
144147
145148 guard !validConfigs. isEmpty else {
146149 ui. warning ( . noValidConfigs)
147- return [ ]
150+ return ( [ ] , [ ] )
148151 }
149152
150- // Check for conflicts
151153 let conflicts = try discovery. detectOutputPathConflicts ( validConfigs)
152- if !conflicts. isEmpty {
153- let formatter = ConflictFormatter ( )
154- formatter. display ( conflicts)
155- }
156-
157- return validConfigs
154+ return ( validConfigs, conflicts)
158155 }
159156
160157 private func prepareConfigsWithCheckpoint(
@@ -199,6 +196,7 @@ extension ExFigCommand {
199196 // swiftlint:disable:next function_body_length
200197 private func executeBatch(
201198 configs: [ ConfigFile ] ,
199+ conflicts: [ OutputPathConflict ] ,
202200 checkpoint: BatchCheckpoint ,
203201 workingDirectory: URL ,
204202 ui: TerminalUI
@@ -254,6 +252,7 @@ extension ExFigCommand {
254252
255253 displayBatchStartInfo (
256254 configs: configs,
255+ conflicts: conflicts,
257256 sharedGranularCache: sharedGranularCache,
258257 ui: ui
259258 )
@@ -403,14 +402,33 @@ extension ExFigCommand {
403402 /// Displays batch start information.
404403 private func displayBatchStartInfo(
405404 configs: [ ConfigFile ] ,
405+ conflicts: [ OutputPathConflict ] ,
406406 sharedGranularCache: SharedGranularCache ? ,
407407 ui: TerminalUI
408408 ) {
409409 ui. info ( " Processing \( configs. count) config(s) with up to \( parallel) parallel workers: " )
410410
411- let headers : [ TableCellStyle ] = [ . plain( " # " ) , . plain( " Config " ) ]
411+ // Build conflict lookup: config name → shared path
412+ var conflictMap : [ String : String ] = [ : ]
413+ for conflict in conflicts {
414+ for configURL in conflict. configs {
415+ conflictMap [ configURL. lastPathComponent] = conflict. path
416+ }
417+ }
418+
419+ let hasConflicts = !conflicts. isEmpty
420+ let headers : [ TableCellStyle ] = hasConflicts
421+ ? [ . plain( " # " ) , . plain( " Config " ) , . plain( " Conflict " ) ]
422+ : [ . plain( " # " ) , . plain( " Config " ) ]
423+
412424 let rows : [ StyledTableRow ] = configs. enumerated ( ) . map { index, config in
413- [ . plain( " \( index + 1 ) " ) , . plain( config. name) ]
425+ if hasConflicts {
426+ let conflictPath = conflictMap [ config. name]
427+ let conflictCell : TableCellStyle = conflictPath. map { . warning( $0) } ?? . plain( " " )
428+ return [ . plain( " \( index + 1 ) " ) , . plain( config. name) , conflictCell]
429+ } else {
430+ return [ . plain( " \( index + 1 ) " ) , . plain( config. name) ]
431+ }
414432 }
415433 NooraUI . shared. table ( headers: headers, rows: rows)
416434
0 commit comments