@@ -257,6 +257,8 @@ const resolveRuntimeConfig = (
257257
258258type DockerIdentityOwner = Pick < TemplateConfig , "containerName" | "serviceName" | "volumeName" | "enableMcpPlaywright" >
259259
260+ type ConflictingProjectEntry = { readonly projectDir : string ; readonly repoUrl : string ; readonly containerName : string ; readonly serviceName : string }
261+
260262type DockerIdentityNamespace = "container" | "composeProject" | "volume"
261263
262264type DockerIdentityClaim = Omit < DockerIdentityConflict , "conflictingProjectDir" > & {
@@ -267,103 +269,63 @@ const resolveDockerIdentityClaims = (
267269 config : DockerIdentityOwner
268270) : ReadonlyArray < DockerIdentityClaim > => [
269271 { namespace : "container" , kind : "containerName" , name : config . containerName } ,
270- ...( config . enableMcpPlaywright
271- ? [
272- {
273- namespace : "container" ,
274- kind : "browserContainerName" ,
275- name : `${ config . containerName } -browser`
276- } satisfies DockerIdentityClaim
277- ]
278- : [ ] ) ,
272+ ...( config . enableMcpPlaywright ? [
273+ { namespace : "container" , kind : "browserContainerName" , name : `${ config . containerName } -browser` } satisfies DockerIdentityClaim
274+ ] : [ ] ) ,
279275 { namespace : "composeProject" , kind : "serviceName" , name : resolveComposeProjectName ( config ) } ,
280276 { namespace : "volume" , kind : "volumeName" , name : config . volumeName } ,
281- ...( config . enableMcpPlaywright
282- ? [
283- {
284- namespace : "volume" ,
285- kind : "browserVolumeName" ,
286- name : `${ config . volumeName } -browser`
287- } satisfies DockerIdentityClaim
288- ]
289- : [ ] ) ,
277+ ...( config . enableMcpPlaywright ? [
278+ { namespace : "volume" , kind : "browserVolumeName" , name : `${ config . volumeName } -browser` } satisfies DockerIdentityClaim
279+ ] : [ ] ) ,
290280 { namespace : "volume" , kind : "bootstrapVolumeName" , name : resolveProjectBootstrapVolumeName ( config ) }
291281]
292282
293- const deleteConflictingProjectsIfNeeded = (
283+ const detectDockerIdentityConflicts = (
294284 resolvedOutDir : string ,
295285 config : DockerIdentityOwner ,
296- force : boolean
297- ) : Effect . Effect < void , DockerIdentityConflictError | PlatformError | DockerCommandError , CreateProjectRuntime > =>
286+ configPaths : ReadonlyArray < string >
287+ ) : Effect . Effect <
288+ { readonly conflicts : ReadonlyArray < DockerIdentityConflict > ; readonly projects : Map < string , ConflictingProjectEntry > } ,
289+ PlatformError , CreateProjectRuntime
290+ > =>
298291 Effect . gen ( function * ( _ ) {
299- const index = yield * _ ( loadProjectIndex ( ) )
300- if ( index === null ) {
301- return
302- }
303-
304292 const candidateClaims = resolveDockerIdentityClaims ( config )
305293 const conflicts : Array < DockerIdentityConflict > = [ ]
306- const conflictingProjects = new Map <
307- string ,
308- {
309- readonly projectDir : string
310- readonly repoUrl : string
311- readonly containerName : string
312- readonly serviceName : string
313- }
314- > ( )
315-
316- for ( const configPath of index . configPaths ) {
317- const status = yield * _ (
318- loadProjectStatus ( configPath ) . pipe (
319- Effect . match ( {
320- onFailure : ( ) => null ,
321- onSuccess : ( value ) => value
322- } )
323- )
324- )
325- if ( status === null || status . projectDir === resolvedOutDir ) {
326- continue
327- }
328-
294+ const projects = new Map < string , ConflictingProjectEntry > ( )
295+ for ( const configPath of configPaths ) {
296+ const status = yield * _ ( loadProjectStatus ( configPath ) . pipe ( Effect . match ( { onFailure : ( ) => null , onSuccess : ( v ) => v } ) ) )
297+ if ( status === null || status . projectDir === resolvedOutDir ) { continue }
329298 const existingClaims = resolveDockerIdentityClaims ( status . config . template )
330299 const sharedClaims = candidateClaims . flatMap ( ( candidate ) =>
331- existingClaims . some (
332- ( existing ) => existing . namespace === candidate . namespace && existing . name === candidate . name
333- )
300+ existingClaims . some ( ( e ) => e . namespace === candidate . namespace && e . name === candidate . name )
334301 ? [ { conflictingProjectDir : status . projectDir , kind : candidate . kind , name : candidate . name } ]
335302 : [ ]
336303 )
337-
338- if ( sharedClaims . length === 0 ) {
339- continue
340- }
341-
342- for ( const claim of sharedClaims ) {
343- conflicts . push ( claim )
344- }
345- conflictingProjects . set ( status . projectDir , {
346- projectDir : status . projectDir ,
347- repoUrl : status . config . template . repoUrl ,
348- containerName : status . config . template . containerName ,
349- serviceName : status . config . template . serviceName
304+ if ( sharedClaims . length === 0 ) { continue }
305+ for ( const claim of sharedClaims ) { conflicts . push ( claim ) }
306+ projects . set ( status . projectDir , {
307+ projectDir : status . projectDir , repoUrl : status . config . template . repoUrl ,
308+ containerName : status . config . template . containerName , serviceName : status . config . template . serviceName
350309 } )
351310 }
311+ return { conflicts, projects }
312+ } )
352313
353- if ( conflicts . length === 0 ) {
354- return
355- }
356-
314+ const deleteConflictingProjectsIfNeeded = (
315+ resolvedOutDir : string ,
316+ config : DockerIdentityOwner ,
317+ force : boolean
318+ ) : Effect . Effect < void , DockerIdentityConflictError | PlatformError | DockerCommandError , CreateProjectRuntime > =>
319+ Effect . gen ( function * ( _ ) {
320+ const index = yield * _ ( loadProjectIndex ( ) )
321+ if ( index === null ) { return }
322+ const { conflicts, projects } = yield * _ ( detectDockerIdentityConflicts ( resolvedOutDir , config , index . configPaths ) )
323+ if ( conflicts . length === 0 ) { return }
357324 if ( ! force ) {
358325 return yield * _ ( Effect . fail ( new DockerIdentityConflictError ( { projectDir : resolvedOutDir , conflicts } ) ) )
359326 }
360-
361- for ( const conflictingProject of conflictingProjects . values ( ) ) {
362- yield * _ (
363- Effect . logWarning (
364- `Force enabled: replacing conflicting docker-git project ${ conflictingProject . projectDir } `
365- )
366- )
327+ for ( const conflictingProject of projects . values ( ) ) {
328+ yield * _ ( Effect . logWarning ( `Force enabled: replacing conflicting docker-git project ${ conflictingProject . projectDir } ` ) )
367329 yield * _ ( deleteDockerGitProject ( conflictingProject ) )
368330 }
369331 } )
0 commit comments