1- import { defaultTemplateConfig } from "@lib/core/domain"
2- import { runDockerInspectContainerRuntimeInfo , type DockerContainerRuntimeInfo } from "@lib/shell/docker"
3- import { buildSshCommand , connectProjectSsh , probeProjectSshReady , type ProjectItem } from "@lib/usecases/projects"
4- import { Effect , pipe } from "effect"
1+ import { type DockerContainerRuntimeInfo , runDockerInspectContainerRuntimeInfo } from "@lib/shell/docker"
2+ import { Effect } from "effect"
53
64import type { OpenCommand } from "@lib/core/domain"
75import { parseGithubRepoUrl , resolveRepoInput } from "@lib/core/repo"
86
97import { getProject , listProjects } from "./api-client.js"
108import type { ApiProjectDetails } from "./api-project-codec.js"
119import type { ProjectResolutionError } from "./host-errors.js"
12- import { connectMenuProjectSshWithUp } from "./menu-api .js"
10+ import { openResolvedProjectSsh } from "./open-project-ssh .js"
1311import { resolveApiProjectItem } from "./project-item.js"
1412
15- type OpenResolvedProjectSshDeps < E , R > = {
16- readonly log : ( message : string ) => Effect . Effect < void , E , R >
17- readonly resolvePreferredItem : ( item : ProjectItem ) => Effect . Effect < ProjectItem | null , E , R >
18- readonly probeReady : ( item : ProjectItem ) => Effect . Effect < boolean , E , R >
19- readonly connect : ( item : ProjectItem ) => Effect . Effect < void , E , R >
20- readonly connectWithUp : ( item : ProjectItem ) => Effect . Effect < void , E , R >
21- }
13+ export {
14+ openResolvedProjectSsh ,
15+ type OpenResolvedProjectSshDeps ,
16+ openResolvedProjectSshEffect
17+ } from "./open-project-ssh.js"
2218
2319type ResolveOpenProjectDeps < E , R > = {
2420 readonly inspectRuntime : ( containerName : string ) => Effect . Effect < DockerContainerRuntimeInfo | null , E , R >
@@ -221,8 +217,9 @@ export const selectOpenProject = (
221217 )
222218}
223219
224- const uniqueContainerNames = ( projects : ReadonlyArray < ApiProjectDetails > ) : ReadonlyArray < string > =>
225- Array . from ( new Set ( projects . map ( ( project ) => project . containerName ) ) )
220+ const uniqueContainerNames = (
221+ projects : ReadonlyArray < ApiProjectDetails >
222+ ) : ReadonlyArray < string > => [ ...new Set ( projects . map ( ( project ) => project . containerName ) ) ]
226223
227224export const resolveRuntimeOwnedProject = < E , R > (
228225 projects : ReadonlyArray < ApiProjectDetails > ,
@@ -257,7 +254,9 @@ export const resolveOpenProjectEffect = <E, R>(
257254 deps : ResolveOpenProjectDeps < E , R >
258255) : Effect . Effect < ApiProjectDetails , ProjectResolutionError | E , R > =>
259256 resolveRuntimeOwnedProject ( projects , selector , deps ) . pipe (
260- Effect . flatMap ( ( ownedProject ) => ownedProject === null ? selectOpenProject ( projects , selector ) : Effect . succeed ( ownedProject ) )
257+ Effect . flatMap ( ( ownedProject ) =>
258+ ownedProject === null ? selectOpenProject ( projects , selector ) : Effect . succeed ( ownedProject )
259+ )
261260 )
262261
263262const listProjectDetails = ( ) =>
@@ -273,99 +272,6 @@ const listProjectDetails = () =>
273272 return details . filter ( ( project ) : project is ApiProjectDetails => project !== null )
274273 } )
275274
276- const withProjectItemIpAddress = (
277- item : ProjectItem ,
278- ipAddress : string
279- ) : ProjectItem => ( {
280- ...item ,
281- ipAddress,
282- sshCommand : buildSshCommand (
283- {
284- ...defaultTemplateConfig ,
285- containerName : item . containerName ,
286- serviceName : item . serviceName ,
287- sshUser : item . sshUser ,
288- sshPort : item . sshPort ,
289- repoUrl : item . repoUrl ,
290- repoRef : item . repoRef ,
291- targetDir : item . targetDir ,
292- envGlobalPath : item . envGlobalPath ,
293- envProjectPath : item . envProjectPath ,
294- codexAuthPath : item . codexAuthPath ,
295- codexSharedAuthPath : item . codexAuthPath ,
296- codexHome : item . codexHome ,
297- clonedOnHostname : item . clonedOnHostname
298- } ,
299- item . sshKeyPath ,
300- ipAddress
301- )
302- } )
303-
304- const sameConnectionTarget = ( left : ProjectItem , right : ProjectItem ) : boolean =>
305- left . ipAddress === right . ipAddress &&
306- left . sshPort === right . sshPort &&
307- left . sshKeyPath === right . sshKeyPath &&
308- left . sshUser === right . sshUser
309-
310- const attemptDirectConnect = < E , R > (
311- item : ProjectItem ,
312- deps : Pick < OpenResolvedProjectSshDeps < E , R > , "connect" | "log" | "probeReady" >
313- ) : Effect . Effect < boolean , E , R > =>
314- deps . probeReady ( item ) . pipe (
315- Effect . flatMap ( ( ready ) =>
316- ready
317- ? pipe (
318- deps . log ( `Opening SSH: ${ item . sshCommand } ` ) ,
319- Effect . zipRight ( deps . connect ( item ) ) ,
320- Effect . as ( true )
321- )
322- : Effect . succeed ( false )
323- )
324- )
325-
326- export const openResolvedProjectSshEffect = < E , R > (
327- item : ProjectItem ,
328- deps : OpenResolvedProjectSshDeps < E , R >
329- ) =>
330- Effect . gen ( function * ( _ ) {
331- const preferredItem = yield * _ ( deps . resolvePreferredItem ( item ) )
332- if ( preferredItem !== null ) {
333- const connected = yield * _ ( attemptDirectConnect ( preferredItem , deps ) )
334- if ( connected ) {
335- return
336- }
337- }
338-
339- const shouldRetryOriginal = preferredItem === null || ! sameConnectionTarget ( preferredItem , item )
340- if ( shouldRetryOriginal ) {
341- const connected = yield * _ ( attemptDirectConnect ( item , deps ) )
342- if ( connected ) {
343- return
344- }
345- }
346-
347- yield * _ ( deps . log ( `Opening SSH: ${ item . sshCommand } ` ) )
348- yield * _ ( deps . connectWithUp ( item ) )
349- } )
350-
351- export const openResolvedProjectSsh = (
352- item : ProjectItem
353- ) =>
354- openResolvedProjectSshEffect ( item , {
355- log : ( message ) => Effect . log ( message ) ,
356- resolvePreferredItem : ( selected ) =>
357- runDockerInspectContainerRuntimeInfo ( process . cwd ( ) , selected . containerName ) . pipe (
358- Effect . map ( ( runtime ) =>
359- runtime !== null && runtime . ipAddress . length > 0
360- ? withProjectItemIpAddress ( selected , runtime . ipAddress )
361- : null
362- )
363- ) ,
364- probeReady : ( selected ) => probeProjectSshReady ( selected ) ,
365- connect : ( selected ) => connectProjectSsh ( selected ) ,
366- connectWithUp : ( selected ) => connectMenuProjectSshWithUp ( selected )
367- } )
368-
369275export const openExistingProjectSsh = (
370276 command : OpenCommand
371277) =>
0 commit comments