@@ -4,6 +4,7 @@ import * as path from "node:path";
44import type { ProjectRef } from "@/common/types/workspace" ;
55import { isSSHRuntime , type RuntimeConfig } from "@/common/types/runtime" ;
66import { PlatformPaths } from "@/common/utils/paths" ;
7+ import type { Runtime } from "@/node/runtime/Runtime" ;
78import {
89 buildLegacyRemoteProjectLayout ,
910 buildRemoteProjectLayout ,
@@ -18,8 +19,7 @@ export interface WorkspaceProjectRepo {
1819 repoCwd : string ;
1920}
2021
21- interface WorkspaceProjectRepoParams {
22- workspaceId : string ;
22+ export interface WorkspaceProjectRuntimeParams {
2323 workspaceName : string ;
2424 workspacePath : string ;
2525 runtimeConfig : RuntimeConfig ;
@@ -28,6 +28,10 @@ interface WorkspaceProjectRepoParams {
2828 projects ?: ProjectRef [ ] ;
2929}
3030
31+ interface WorkspaceProjectRepoParams extends WorkspaceProjectRuntimeParams {
32+ workspaceId : string ;
33+ }
34+
3135interface WorkspaceProjectStorageKeyParams {
3236 projectPath : string ;
3337 projectName ?: string ;
@@ -138,8 +142,14 @@ export function getWorkspaceProjectStorageKeys(
138142 return storageKeys ;
139143}
140144
145+ function hasMultipleWorkspaceProjects (
146+ params : Pick < WorkspaceProjectRuntimeParams , "projects" >
147+ ) : boolean {
148+ return ( params . projects ?. length ?? 0 ) > 1 ;
149+ }
150+
141151export function getWorkspacePathHintForProject (
142- params : WorkspaceProjectRepoParams ,
152+ params : WorkspaceProjectRuntimeParams ,
143153 targetProjectPath : string
144154) : string | undefined {
145155 if ( ! isSSHRuntime ( params . runtimeConfig ) ) {
@@ -172,6 +182,49 @@ export function getWorkspacePathHintForProject(
172182 return undefined ;
173183}
174184
185+ /**
186+ * Recreate the runtime for one project inside an existing workspace.
187+ *
188+ * Why: multi-project SSH workspaces sometimes need a sibling checkout hint derived from the
189+ * persisted workspace root, while single-project workspaces should always keep using their exact
190+ * checkout path from config.
191+ */
192+ export function createRuntimeForWorkspaceProject (
193+ params : WorkspaceProjectRuntimeParams ,
194+ targetProjectPath : string
195+ ) : Runtime {
196+ const workspacePath = hasMultipleWorkspaceProjects ( params )
197+ ? getWorkspacePathHintForProject ( params , targetProjectPath )
198+ : params . workspacePath ;
199+
200+ return createRuntime ( params . runtimeConfig , {
201+ projectPath : targetProjectPath ,
202+ workspaceName : params . workspaceName ,
203+ workspacePath,
204+ } ) ;
205+ }
206+
207+ export function resolveWorkspacePathForProject (
208+ params : WorkspaceProjectRuntimeParams ,
209+ targetProjectPath : string ,
210+ runtime = createRuntimeForWorkspaceProject ( params , targetProjectPath )
211+ ) : string {
212+ if ( ! hasMultipleWorkspaceProjects ( params ) ) {
213+ assert (
214+ params . workspacePath . trim ( ) . length > 0 ,
215+ "resolveWorkspacePathForProject: workspacePath must be non-empty"
216+ ) ;
217+ return params . workspacePath ;
218+ }
219+
220+ const workspacePath = runtime . getWorkspacePath ( targetProjectPath , params . workspaceName ) ;
221+ assert (
222+ workspacePath . trim ( ) . length > 0 ,
223+ `resolveWorkspacePathForProject: workspacePath missing for ${ targetProjectPath } `
224+ ) ;
225+ return workspacePath ;
226+ }
227+
175228export function getWorkspaceProjectRepos (
176229 params : WorkspaceProjectRepoParams
177230) : WorkspaceProjectRepo [ ] {
@@ -197,25 +250,9 @@ export function getWorkspaceProjectRepos(
197250 projectName : params . projectName ,
198251 projects : params . projects ,
199252 } ) ;
200- const isMultiProject = projectStorageKeys . length > 1 ;
201253
202254 const repos = projectStorageKeys . map ( ( project ) => {
203- const sshWorkspacePathHint = isMultiProject
204- ? getWorkspacePathHintForProject ( params , project . projectPath )
205- : undefined ;
206-
207- const repoCwd = ! isMultiProject
208- ? params . workspacePath
209- : ( sshWorkspacePathHint ??
210- createRuntime ( params . runtimeConfig , {
211- projectPath : project . projectPath ,
212- workspaceName : params . workspaceName ,
213- } ) . getWorkspacePath ( project . projectPath , params . workspaceName ) ) ;
214-
215- assert (
216- repoCwd . trim ( ) . length > 0 ,
217- `getWorkspaceProjectRepos: repoCwd missing for ${ project . projectName } `
218- ) ;
255+ const repoCwd = resolveWorkspacePathForProject ( params , project . projectPath ) ;
219256
220257 return {
221258 projectPath : project . projectPath ,
0 commit comments