mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix(cli): block team workspace rclone sync
Signed-off-by: Drew Cain <groksrc@gmail.com>
This commit is contained in:
committed by
Paul Hernandez
parent
ff5d872a8c
commit
a2276a8a04
@@ -26,11 +26,20 @@ from basic_memory.cli.commands.routing import force_routing
|
||||
from basic_memory.config import ConfigManager, ProjectEntry
|
||||
from basic_memory.mcp.async_client import get_client
|
||||
from basic_memory.mcp.clients import ProjectClient
|
||||
from basic_memory.mcp.project_context import get_available_workspaces
|
||||
from basic_memory.schemas.cloud import WorkspaceInfo
|
||||
from basic_memory.schemas.project_info import ProjectItem
|
||||
from basic_memory.utils import generate_permalink, normalize_project_path
|
||||
|
||||
console = Console()
|
||||
|
||||
TEAM_WORKSPACE_SYNC_UNSUPPORTED = (
|
||||
"Local rclone sync/bisync is supported only for Personal workspaces.\n"
|
||||
"Team workspaces are accessed through the cloud API/MCP and do not support "
|
||||
"local multi-user bisync.\n"
|
||||
"Use `bm project list --workspace <workspace>` to inspect Team projects."
|
||||
)
|
||||
|
||||
|
||||
# --- Shared helpers ---
|
||||
|
||||
@@ -52,6 +61,54 @@ def _require_cloud_credentials(config) -> None:
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
async def _get_workspace_for_project(name: str, config) -> WorkspaceInfo:
|
||||
"""Resolve the cloud workspace targeted by a project-scoped sync command."""
|
||||
workspaces = await get_available_workspaces()
|
||||
if not workspaces:
|
||||
raise ValueError("No accessible cloud workspaces found for this account")
|
||||
|
||||
entry = config.projects.get(name)
|
||||
workspace_id = entry.workspace_id if entry and entry.workspace_id else config.default_workspace
|
||||
if workspace_id:
|
||||
workspace = next(
|
||||
(item for item in workspaces if item.tenant_id == workspace_id),
|
||||
None,
|
||||
)
|
||||
if workspace is None:
|
||||
raise ValueError(
|
||||
f"Configured workspace '{workspace_id}' for project '{name}' is not accessible"
|
||||
)
|
||||
return workspace
|
||||
|
||||
default_workspaces = [item for item in workspaces if item.is_default]
|
||||
if len(default_workspaces) == 1:
|
||||
return default_workspaces[0]
|
||||
|
||||
if len(workspaces) == 1:
|
||||
return workspaces[0]
|
||||
|
||||
raise ValueError(
|
||||
f"Project '{name}' does not have an unambiguous cloud workspace. "
|
||||
"Set a default workspace with `bm cloud workspace set-default <workspace>` "
|
||||
"or attach the project with `bm project set-cloud <name> --workspace <workspace>`."
|
||||
)
|
||||
|
||||
|
||||
def _require_personal_workspace(name: str, config) -> WorkspaceInfo:
|
||||
"""Exit before rclone work when the target workspace is not personal."""
|
||||
try:
|
||||
workspace = run_with_cleanup(_get_workspace_for_project(name, config))
|
||||
except Exception as exc:
|
||||
console.print(f"[red]Error resolving workspace for project '{name}': {exc}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
if workspace.workspace_type != "personal":
|
||||
console.print(f"[red]{TEAM_WORKSPACE_SYNC_UNSUPPORTED}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
return workspace
|
||||
|
||||
|
||||
async def _get_cloud_project(name: str) -> ProjectItem | None:
|
||||
"""Fetch a project by name from the cloud API."""
|
||||
async with get_client(project_name=name) as client:
|
||||
@@ -103,6 +160,7 @@ def sync_project_command(
|
||||
"""
|
||||
config = ConfigManager().config
|
||||
_require_cloud_credentials(config)
|
||||
_require_personal_workspace(name, config)
|
||||
|
||||
try:
|
||||
# Get tenant info for bucket name
|
||||
@@ -152,6 +210,7 @@ def bisync_project_command(
|
||||
"""
|
||||
config = ConfigManager().config
|
||||
_require_cloud_credentials(config)
|
||||
_require_personal_workspace(name, config)
|
||||
|
||||
try:
|
||||
# Get tenant info for bucket name
|
||||
@@ -210,6 +269,7 @@ def check_project_command(
|
||||
"""
|
||||
config = ConfigManager().config
|
||||
_require_cloud_credentials(config)
|
||||
_require_personal_workspace(name, config)
|
||||
|
||||
try:
|
||||
# Get tenant info for bucket name
|
||||
@@ -253,6 +313,10 @@ def bisync_reset(
|
||||
"""
|
||||
import shutil
|
||||
|
||||
config = ConfigManager().config
|
||||
if _has_cloud_credentials(config):
|
||||
_require_personal_workspace(name, config)
|
||||
|
||||
try:
|
||||
state_path = get_project_bisync_state(name)
|
||||
|
||||
@@ -288,6 +352,7 @@ def setup_project_sync(
|
||||
config_manager = ConfigManager()
|
||||
config = config_manager.config
|
||||
_require_cloud_credentials(config)
|
||||
_require_personal_workspace(name, config)
|
||||
|
||||
async def _verify_project_exists():
|
||||
"""Verify the project exists on cloud by listing all projects."""
|
||||
|
||||
Reference in New Issue
Block a user