22
33from basic_memory .cli .commands .cloud .api_client import make_api_request
44from basic_memory .config import ConfigManager
5+ from basic_memory .mcp .async_client import resolve_configured_workspace
56from basic_memory .schemas .cloud import (
67 CloudProjectList ,
78 CloudProjectCreateRequest ,
@@ -16,8 +17,25 @@ class CloudUtilsError(Exception):
1617 pass
1718
1819
20+ def _workspace_headers (
21+ * ,
22+ project_name : str | None = None ,
23+ workspace : str | None = None ,
24+ ) -> dict [str , str ]:
25+ """Build optional workspace headers using the CLI config resolution chain."""
26+ resolved_workspace = resolve_configured_workspace (
27+ project_name = project_name ,
28+ workspace = workspace ,
29+ )
30+ if resolved_workspace is None :
31+ return {}
32+ return {"X-Workspace-ID" : resolved_workspace }
33+
34+
1935async def fetch_cloud_projects (
2036 * ,
37+ project_name : str | None = None ,
38+ workspace : str | None = None ,
2139 api_request = make_api_request ,
2240) -> CloudProjectList :
2341 """Fetch list of projects from cloud API.
@@ -30,7 +48,11 @@ async def fetch_cloud_projects(
3048 config = config_manager .config
3149 host_url = config .cloud_host .rstrip ("/" )
3250
33- response = await api_request (method = "GET" , url = f"{ host_url } /proxy/v2/projects/" )
51+ response = await api_request (
52+ method = "GET" ,
53+ url = f"{ host_url } /proxy/v2/projects/" ,
54+ headers = _workspace_headers (project_name = project_name , workspace = workspace ),
55+ )
3456
3557 return CloudProjectList .model_validate (response .json ())
3658 except Exception as e :
@@ -40,12 +62,14 @@ async def fetch_cloud_projects(
4062async def create_cloud_project (
4163 project_name : str ,
4264 * ,
65+ workspace : str | None = None ,
4366 api_request = make_api_request ,
4467) -> CloudProjectCreateResponse :
4568 """Create a new project on cloud.
4669
4770 Args:
4871 project_name: Name of project to create
72+ workspace: Optional workspace override for tenant-scoped project creation
4973
5074 Returns:
5175 CloudProjectCreateResponse with project details from API
@@ -67,7 +91,10 @@ async def create_cloud_project(
6791 response = await api_request (
6892 method = "POST" ,
6993 url = f"{ host_url } /proxy/v2/projects/" ,
70- headers = {"Content-Type" : "application/json" },
94+ headers = {
95+ "Content-Type" : "application/json" ,
96+ ** _workspace_headers (project_name = project_name , workspace = workspace ),
97+ },
7198 json_data = project_data .model_dump (),
7299 )
73100
@@ -91,18 +118,28 @@ async def sync_project(project_name: str, force_full: bool = False) -> None:
91118 raise CloudUtilsError (f"Failed to sync project '{ project_name } ': { e } " ) from e
92119
93120
94- async def project_exists (project_name : str , * , api_request = make_api_request ) -> bool :
121+ async def project_exists (
122+ project_name : str ,
123+ * ,
124+ workspace : str | None = None ,
125+ api_request = make_api_request ,
126+ ) -> bool :
95127 """Check if a project exists on cloud.
96128
97129 Args:
98130 project_name: Name of project to check
131+ workspace: Optional workspace override for tenant-scoped project lookup
99132
100133 Returns:
101134 True if project exists, False otherwise
135+
136+ Raises:
137+ CloudUtilsError: If the project list cannot be fetched from cloud
102138 """
103- try :
104- projects = await fetch_cloud_projects (api_request = api_request )
105- project_names = {p .name for p in projects .projects }
106- return project_name in project_names
107- except Exception :
108- return False
139+ projects = await fetch_cloud_projects (
140+ project_name = project_name ,
141+ workspace = workspace ,
142+ api_request = api_request ,
143+ )
144+ project_names = {p .name for p in projects .projects }
145+ return project_name in project_names
0 commit comments