From 12d77d0128e4d82e5ddc1a4ab7e873ddaa22e130 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 17 Apr 2025 20:33:20 -0600 Subject: [PATCH] refactor: rename project to cubbi --- CLAUDE.md | 6 +- README.md | 188 ++++++++------- {mcontainer => cubbi}/__init__.py | 2 +- {mcontainer => cubbi}/__main__.py | 0 {mcontainer => cubbi}/cli.py | 81 ++++--- {mcontainer => cubbi}/config.py | 16 +- {mcontainer => cubbi}/container.py | 94 ++++---- .../cubbi_inspector_entrypoint.sh | 0 {mcontainer => cubbi}/images/__init__.py | 0 {mcontainer => cubbi}/images/base.py | 0 {mcontainer => cubbi}/images/goose/Dockerfile | 10 +- {mcontainer => cubbi}/images/goose/README.md | 12 +- .../images/goose/cubbi-image.yaml | 20 +- .../images/goose/cubbi-init.sh | 117 +++++---- .../images/goose/entrypoint.sh | 2 +- .../images/goose/init-status.sh | 2 +- .../images/goose/update-goose-config.py | 4 +- {mcontainer => cubbi}/mcp.py | 32 +-- {mcontainer => cubbi}/models.py | 0 {mcontainer => cubbi}/session.py | 6 +- {mcontainer => cubbi}/user_config.py | 12 +- {mcontainer => cubbi}/utils/git.py | 0 docs/specs/1_SPECIFICATIONS.md | 228 +++++++++--------- docs/specs/2_MCP_SERVER.md | 40 +-- pyproject.toml | 8 +- tests/conftest.py | 20 +- tests/test_cli.py | 6 +- tests/test_config_commands.py | 12 +- tests/test_integration_docker.py | 10 +- tests/test_mcp_commands.py | 16 +- tests/test_mcp_port_binding.py | 2 +- tests/test_session_commands.py | 18 +- uv.lock | 78 +++--- 33 files changed, 525 insertions(+), 517 deletions(-) rename {mcontainer => cubbi}/__init__.py (50%) rename {mcontainer => cubbi}/__main__.py (100%) rename {mcontainer => cubbi}/cli.py (96%) rename {mcontainer => cubbi}/config.py (92%) rename {mcontainer => cubbi}/container.py (92%) rename mcontainer/mc_inspector_entrypoint.sh => cubbi/cubbi_inspector_entrypoint.sh (100%) rename {mcontainer => cubbi}/images/__init__.py (100%) rename {mcontainer => cubbi}/images/base.py (100%) rename {mcontainer => cubbi}/images/goose/Dockerfile (88%) rename {mcontainer => cubbi}/images/goose/README.md (68%) rename mcontainer/images/goose/mc-image.yaml => cubbi/images/goose/cubbi-image.yaml (76%) rename mcontainer/images/goose/mc-init.sh => cubbi/images/goose/cubbi-init.sh (53%) rename {mcontainer => cubbi}/images/goose/entrypoint.sh (90%) rename {mcontainer => cubbi}/images/goose/init-status.sh (96%) rename {mcontainer => cubbi}/images/goose/update-goose-config.py (97%) rename {mcontainer => cubbi}/mcp.py (97%) rename {mcontainer => cubbi}/models.py (100%) rename {mcontainer => cubbi}/session.py (92%) rename {mcontainer => cubbi}/user_config.py (97%) rename {mcontainer => cubbi}/utils/git.py (100%) diff --git a/CLAUDE.md b/CLAUDE.md index a4cf9ce..b40fdb8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,12 +1,12 @@ -# Monadical Container Development Guide +# Cubbi Container Development Guide ## Build Commands ```bash # Install dependencies using uv (Astral) uv sync -# Run MC CLI -uv run -m mcontainer.cli +# Run Cubbi CLI +uv run -m cubbi.cli ``` ## Lint/Test Commands diff --git a/README.md b/README.md index 9df3414..691e8aa 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# MC - Monadical Container Tool +# Cubbi - Container Tool -MC (Monadical Container) is a command-line tool for managing ephemeral +Cubbi is a command-line tool for managing ephemeral containers that run AI tools and development environments. It works with both local Docker and a dedicated remote web service that manages containers in a -Docker-in-Docker (DinD) environment. MC also supports connecting to MCP (Model Control Protocol) servers to extend AI tools with additional capabilities. +Docker-in-Docker (DinD) environment. Cubbi also supports connecting to MCP (Model Control Protocol) servers to extend AI tools with additional capabilities. ## Quick Reference -- `mc session create` - Create a new session -- `mcx` - Shortcut for `mc session create` -- `mcx .` - Mount the current directory -- `mcx /path/to/dir` - Mount a specific directory -- `mcx https://github.com/user/repo` - Clone a repository +- `cubbi session create` - Create a new session +- `cubbix` - Shortcut for `cubbi session create` +- `cubbix .` - Mount the current directory +- `cubbix /path/to/dir` - Mount a specific directory +- `cubbix https://github.com/user/repo` - Clone a repository ## Requirements @@ -21,104 +21,110 @@ Docker-in-Docker (DinD) environment. MC also supports connecting to MCP (Model C ```bash # Clone the repository -git clone https://github.com/monadical/mcontainer.git +git clone https://github.com/monadical/cubbi.git # Install the tool locally # (with editable, so you can update the code and work with it) -cd mcontainer +cd cubbi uv tool install --with-editable . . -# Then you could use the tool as `mc` -mc --help +# Then you could use the tool as `cubbi` +cubbi --help +``` + +Important: compile your first image + +```bash +cubbi image build goose ``` ## Basic Usage ```bash # Show help message (displays available commands) -mc +cubbi -# Create a new session with the default image (using mcx alias) -mcx +# Create a new session with the default image (using cubbix alias) +cubbix # Create a session and run an initial command before the shell starts -mcx --run "echo 'Setup complete'; ls -l" +cubbix --run "echo 'Setup complete'; ls -l" # List all active sessions -mc session list +cubbi session list # Connect to a specific session -mc session connect SESSION_ID +cubbi session connect SESSION_ID # Close a session when done -mc session close SESSION_ID +cubbi session close SESSION_ID # Create a session with a specific image -mcx --image goose +cubbix --image goose # Create a session with environment variables -mcx -e VAR1=value1 -e VAR2=value2 +cubbix -e VAR1=value1 -e VAR2=value2 # Mount custom volumes (similar to Docker's -v flag) -mcx -v /local/path:/container/path -mcx -v ~/data:/data -v ./configs:/etc/app/config +cubbix -v /local/path:/container/path +cubbix -v ~/data:/data -v ./configs:/etc/app/config # Mount a local directory (current directory or specific path) -mcx . -mcx /path/to/project +cubbix . +cubbix /path/to/project # Connect to external Docker networks -mcx --network teamnet --network dbnet +cubbix --network teamnet --network dbnet # Connect to MCP servers for extended capabilities -mcx --mcp github --mcp jira +cubbix --mcp github --mcp jira # Clone a Git repository -mcx https://github.com/username/repo +cubbix https://github.com/username/repo -# Using the mcx shortcut (equivalent to mc session create) -mcx # Creates a session without mounting anything -mcx . # Mounts the current directory -mcx /path/to/project # Mounts the specified directory -mcx https://github.com/username/repo # Clones the repository +# Using the cubbix shortcut (equivalent to cubbi session create) +cubbix # Creates a session without mounting anything +cubbix . # Mounts the current directory +cubbix /path/to/project # Mounts the specified directory +cubbix https://github.com/username/repo # Clones the repository # Shorthand with MCP servers -mcx https://github.com/username/repo --mcp github +cubbix https://github.com/username/repo --mcp github # Shorthand with an initial command -mcx . --run "apt-get update && apt-get install -y my-package" +cubbix . --run "apt-get update && apt-get install -y my-package" # Enable SSH server in the container -mcx --ssh +cubbix --ssh ``` ## Image Management -MC includes a image management system that allows you to build, manage, and use Docker images for different AI tools: +Cubbi includes an image management system that allows you to build, manage, and use Docker images for different AI tools: ```bash # List available images -mc image list +cubbi image list # Get detailed information about an image -mc image info goose +cubbi image info goose # Build an image -mc image build goose +cubbi image build goose # Build and push an image -mc image build goose --push +cubbi image build goose --push ``` -Images are defined in the `mcontainer/images/` directory, with each subdirectory containing: +Images are defined in the `cubbi/images/` directory, with each subdirectory containing: - `Dockerfile`: Docker image definition - `entrypoint.sh`: Container entrypoint script -- `mc-init.sh`: Standardized initialization script -- `mc-image.yaml`: Image metadata and configuration +- `cubbi-init.sh`: Standardized initialization script +- `cubbi-image.yaml`: Image metadata and configuration - `README.md`: Image documentation -MC automatically discovers and loads image definitions from the YAML files. +Cubbi automatically discovers and loads image definitions from the YAML files. ``` ## Development @@ -139,28 +145,28 @@ uvx ruff format . ## Configuration -MC supports user-specific configuration via a YAML file located at `~/.config/mc/config.yaml`. This allows you to set default values and configure service credentials. +Cubbi supports user-specific configuration via a YAML file located at `~/.config/cubbi/config.yaml`. This allows you to set default values and configure service credentials. ### Managing Configuration ```bash # View all configuration -mc config list +cubbi config list # Get a specific configuration value -mc config get langfuse.url +cubbi config get langfuse.url # Set configuration values -mc config set langfuse.url "https://cloud.langfuse.com" -mc config set langfuse.public_key "pk-lf-..." -mc config set langfuse.secret_key "sk-lf-..." +cubbi config set langfuse.url "https://cloud.langfuse.com" +cubbi config set langfuse.public_key "pk-lf-..." +cubbi config set langfuse.secret_key "sk-lf-..." # Set API keys for various services -mc config set openai.api_key "sk-..." -mc config set anthropic.api_key "sk-ant-..." +cubbi config set openai.api_key "sk-..." +cubbi config set anthropic.api_key "sk-ant-..." # Reset configuration to defaults -mc config reset +cubbi config reset ``` ### Default Networks Configuration @@ -169,13 +175,13 @@ You can configure default networks that will be applied to every new session: ```bash # List default networks -mc config network list +cubbi config network list # Add a network to defaults -mc config network add teamnet +cubbi config network add teamnet # Remove a network from defaults -mc config network remove teamnet +cubbi config network remove teamnet ``` ### Default Volumes Configuration @@ -184,13 +190,13 @@ You can configure default volumes that will be automatically mounted in every ne ```bash # List default volumes -mc config volume list +cubbi config volume list # Add a volume to defaults -mc config volume add /local/path:/container/path +cubbi config volume add /local/path:/container/path # Remove a volume from defaults (will prompt if multiple matches found) -mc config volume remove /local/path +cubbi config volume remove /local/path ``` Default volumes will be combined with any volumes specified using the `-v` flag when creating a session. @@ -201,35 +207,35 @@ You can configure default MCP servers that sessions will automatically connect t ```bash # List default MCP servers -mc config mcp list +cubbi config mcp list # Add an MCP server to defaults -mc config mcp add github +cubbi config mcp add github # Remove an MCP server from defaults -mc config mcp remove github +cubbi config mcp remove github ``` When adding new MCP servers, they are added to defaults by default. Use the `--no-default` flag to prevent this: ```bash # Add an MCP server without adding it to defaults -mc mcp add github ghcr.io/mcp/github:latest --no-default -mc mcp add-remote jira https://jira-mcp.example.com/sse --no-default +cubbi mcp add github ghcr.io/mcp/github:latest --no-default +cubbi mcp add-remote jira https://jira-mcp.example.com/sse --no-default ``` When creating sessions, if no MCP server is specified with `--mcp`, the default MCP servers will be used automatically. ### External Network Connectivity -MC containers can connect to external Docker networks, allowing them to communicate with other services in those networks: +Cubbi containers can connect to external Docker networks, allowing them to communicate with other services in those networks: ```bash # Create a session connected to external networks -mc session create --network teamnet --network dbnet +cubbi session create --network teamnet --network dbnet ``` -**Important**: Networks must be "attachable" to be joined by MC containers. Here's how to create attachable networks: +**Important**: Networks must be "attachable" to be joined by Cubbi containers. Here's how to create attachable networks: ```bash # Create an attachable network with Docker @@ -247,12 +253,12 @@ services: networks: teamnet: driver: bridge - attachable: true # This is required for MC containers to connect + attachable: true # This is required for Cubbi containers to connect ``` ### Service Credentials -Service credentials like API keys configured in `~/.config/mc/config.yaml` are automatically passed to containers as environment variables: +Service credentials like API keys configured in `~/.config/cubbi/config.yaml` are automatically passed to containers as environment variables: | Config Setting | Environment Variable | |----------------|---------------------| @@ -266,7 +272,7 @@ Service credentials like API keys configured in `~/.config/mc/config.yaml` are a ## MCP Server Management -MCP (Model Control Protocol) servers provide tool-calling capabilities to AI models, enhancing their ability to interact with external services, databases, and systems. MC supports multiple types of MCP servers: +MCP (Model Control Protocol) servers provide tool-calling capabilities to AI models, enhancing their ability to interact with external services, databases, and systems. Cubbi supports multiple types of MCP servers: 1. **Remote HTTP SSE servers** - External MCP servers accessed over HTTP 2. **Docker-based MCP servers** - Local MCP servers running in Docker containers @@ -276,56 +282,56 @@ MCP (Model Control Protocol) servers provide tool-calling capabilities to AI mod ```bash # List all configured MCP servers and their status -mc mcp list +cubbi mcp list # View detailed status of an MCP server -mc mcp status github +cubbi mcp status github # Start/stop/restart individual MCP servers -mc mcp start github -mc mcp stop github -mc mcp restart github +cubbi mcp start github +cubbi mcp stop github +cubbi mcp restart github # Start all MCP servers at once -mc mcp start --all +cubbi mcp start --all # Stop and remove all MCP servers at once -mc mcp stop --all +cubbi mcp stop --all # Run the MCP Inspector to visualize and interact with MCP servers # It automatically joins all MCP networks for seamless DNS resolution # Uses two ports: frontend UI (default: 5173) and backend API (default: 3000) -mc mcp inspector +cubbi mcp inspector # Run the MCP Inspector with custom ports -mc mcp inspector --client-port 6173 --server-port 6174 +cubbi mcp inspector --client-port 6173 --server-port 6174 # Run the MCP Inspector in detached mode -mc mcp inspector --detach +cubbi mcp inspector --detach # Stop the MCP Inspector -mc mcp inspector --stop +cubbi mcp inspector --stop # View MCP server logs -mc mcp logs github +cubbi mcp logs github # Remove an MCP server configuration -mc mcp remove github +cubbi mcp remove github ``` ### Adding MCP Servers -MC supports different types of MCP servers: +Cubbi supports different types of MCP servers: ```bash # Add a remote HTTP SSE MCP server -mc mcp remote add github http://my-mcp-server.example.com/sse --header "Authorization=Bearer token123" +cubbi mcp remote add github http://my-mcp-server.example.com/sse --header "Authorization=Bearer token123" # Add a Docker-based MCP server -mc mcp docker add github mcp/github:latest --command "github-mcp" --env GITHUB_TOKEN=ghp_123456 +cubbi mcp docker add github mcp/github:latest --command "github-mcp" --env GITHUB_TOKEN=ghp_123456 # Add a proxy-based MCP server (for stdio-to-SSE conversion) -mc mcp add github ghcr.io/mcp/github:latest --proxy-image ghcr.io/sparfenyuk/mcp-proxy:latest --command "github-mcp" --sse-port 8080 --no-default +cubbi mcp add github ghcr.io/mcp/github:latest --proxy-image ghcr.io/sparfenyuk/mcp-proxy:latest --command "github-mcp" --sse-port 8080 --no-default ``` ### Using MCP Servers with Sessions @@ -334,13 +340,13 @@ MCP servers can be attached to sessions when they are created: ```bash # Create a session with a single MCP server -mc session create --mcp github +cubbi session create --mcp github # Create a session with multiple MCP servers -mc session create --mcp github --mcp jira +cubbi session create --mcp github --mcp jira # Using MCP with a project repository -mc github.com/username/repo --mcp github +cubbi github.com/username/repo --mcp github ``` MCP servers are persistent and can be shared between sessions. They continue running even when sessions are closed, allowing for efficient reuse across multiple sessions. diff --git a/mcontainer/__init__.py b/cubbi/__init__.py similarity index 50% rename from mcontainer/__init__.py rename to cubbi/__init__.py index dae98c0..e373fb8 100644 --- a/mcontainer/__init__.py +++ b/cubbi/__init__.py @@ -1,5 +1,5 @@ """ -MC - Monadical Container Tool +Cubbi - Cubbi Container Tool """ __version__ = "0.1.0" diff --git a/mcontainer/__main__.py b/cubbi/__main__.py similarity index 100% rename from mcontainer/__main__.py rename to cubbi/__main__.py diff --git a/mcontainer/cli.py b/cubbi/cli.py similarity index 96% rename from mcontainer/cli.py rename to cubbi/cli.py index ff8b5fb..4b043ea 100644 --- a/mcontainer/cli.py +++ b/cubbi/cli.py @@ -1,5 +1,5 @@ """ -CLI for Monadical Container Tool. +CLI for Cubbi Container Tool. """ import logging @@ -24,10 +24,10 @@ logging.basicConfig( handlers=[logging.StreamHandler()], ) -app = typer.Typer(help="Monadical Container Tool", no_args_is_help=True) -session_app = typer.Typer(help="Manage MC sessions", no_args_is_help=True) -image_app = typer.Typer(help="Manage MC images", no_args_is_help=True) -config_app = typer.Typer(help="Manage MC configuration", no_args_is_help=True) +app = typer.Typer(help="Cubbi Container Tool", no_args_is_help=True) +session_app = typer.Typer(help="Manage Cubbi sessions", no_args_is_help=True) +image_app = typer.Typer(help="Manage Cubbi images", no_args_is_help=True) +config_app = typer.Typer(help="Manage Cubbi configuration", no_args_is_help=True) mcp_app = typer.Typer(help="Manage MCP servers", no_args_is_help=True) app.add_typer(session_app, name="session", no_args_is_help=True) app.add_typer(image_app, name="image", no_args_is_help=True) @@ -49,10 +49,10 @@ def main( False, "--verbose", "-v", help="Enable verbose logging" ), ) -> None: - """Monadical Container Tool + """Cubbi Container Tool - Run 'mc session create' to create a new session. - Use 'mcx' as a shortcut for 'mc session create'. + Run 'cubbi session create' to create a new session. + Use 'cubbix' as a shortcut for 'cubbi session create'. """ # Set log level based on verbose flag if verbose: @@ -61,19 +61,19 @@ def main( @app.command() def version() -> None: - """Show MC version information""" + """Show Cubbi version information""" from importlib.metadata import version as get_version try: - version_str = get_version("mcontainer") - console.print(f"MC - Monadical Container Tool v{version_str}") + version_str = get_version("cubbi") + console.print(f"Cubbi - Cubbi Container Tool v{version_str}") except Exception: - console.print("MC - Monadical Container Tool (development version)") + console.print("Cubbi - Cubbi Container Tool (development version)") @session_app.command("list") def list_sessions() -> None: - """List active MC sessions""" + """List active Cubbi sessions""" sessions = container_manager.list_sessions() if not sessions: @@ -168,7 +168,7 @@ def create_session( ), ssh: bool = typer.Option(False, "--ssh", help="Start SSH server in the container"), ) -> None: - """Create a new MC session + """Create a new Cubbi session If a local directory path is provided, it will be mounted at /app in the container. If a repository URL is provided, it will be cloned into /app during initialization. @@ -304,11 +304,11 @@ def create_session( if no_connect: console.print("\nConnection skipped due to --no-connect.") console.print( - f"Connect manually with:\n mc session connect {session.id}" + f"Connect manually with:\n cubbi session connect {session.id}" ) elif not auto_connect: console.print( - f"\nAuto-connect disabled. Connect with:\n mc session connect {session.id}" + f"\nAuto-connect disabled. Connect with:\n cubbi session connect {session.id}" ) else: console.print("[red]Failed to create session[/red]") @@ -319,7 +319,7 @@ def close_session( session_id: Optional[str] = typer.Argument(None, help="Session ID to close"), all_sessions: bool = typer.Option(False, "--all", help="Close all active sessions"), ) -> None: - """Close a MC session or all sessions""" + """Close a Cubbi session or all sessions""" if all_sessions: # Get sessions first to display them sessions = container_manager.list_sessions() @@ -364,7 +364,7 @@ def close_session( def connect_session( session_id: str = typer.Argument(..., help="Session ID to connect to"), ) -> None: - """Connect to a MC session""" + """Connect to a Cubbi session""" console.print(f"Connecting to session {session_id}...") success = container_manager.connect_session(session_id) @@ -380,7 +380,7 @@ def session_logs( False, "--init", "-i", help="Show initialization logs instead of container logs" ), ) -> None: - """Stream logs from a MC session""" + """Stream logs from a Cubbi session""" if init: # Show initialization logs if follow: @@ -407,7 +407,7 @@ def session_logs( @image_app.command("list") def list_images() -> None: - """List available MC images""" + """List available Cubbi images""" images = config_manager.list_images() if not images: @@ -455,7 +455,7 @@ def build_image( return # Build image name - docker_image_name = f"monadical/mc-{image_name}:{tag}" + docker_image_name = f"monadical/cubbi-{image_name}:{tag}" # Build the image with console.status(f"Building image {docker_image_name}..."): @@ -1472,7 +1472,7 @@ def run_mcp_inspector( # If stop flag is set, stop all running MCP Inspectors if stop: containers = client.containers.list( - all=True, filters={"label": "mc.mcp.inspector=true"} + all=True, filters={"label": "cubbi.mcp.inspector=true"} ) if not containers: console.print("[yellow]No running MCP Inspector instances found[/yellow]") @@ -1491,7 +1491,7 @@ def run_mcp_inspector( # Check if inspector is already running all_inspectors = client.containers.list( - all=True, filters={"label": "mc.mcp.inspector=true"} + all=True, filters={"label": "cubbi.mcp.inspector=true"} ) # Stop any existing inspectors first @@ -1535,7 +1535,7 @@ def run_mcp_inspector( return # Container name with timestamp to avoid conflicts - container_name = f"mc_mcp_inspector_{int(time.time())}" + container_name = f"cubbi_mcp_inspector_{int(time.time())}" with console.status("Starting MCP Inspector..."): # Get MCP servers from configuration @@ -1568,7 +1568,7 @@ def run_mcp_inspector( mcp_name = mcp.get("name") try: # Get the container name for this MCP - container_name = f"mc_mcp_{mcp_name}" + container_name = f"cubbi_mcp_{mcp_name}" container = None # Try to find the container @@ -1619,7 +1619,7 @@ def run_mcp_inspector( # Make sure we have at least one network to connect to if not mcp_networks_to_connect: # Create an MCP-specific network if none exists - network_name = "mc-mcp-network" + network_name = "cubbi-mcp-network" console.print("No MCP networks found, creating a default one") try: networks = client.networks.list(names=[network_name]) @@ -1679,7 +1679,8 @@ exec npm start # Write the script to a temp file script_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "mc_inspector_entrypoint.sh" + os.path.dirname(os.path.abspath(__file__)), + "cubbi_inspector_entrypoint.sh", ) with open(script_path, "w") as f: f.write(script_content) @@ -1696,7 +1697,7 @@ exec npm start # Check if existing container with the same name exists, and remove it try: - existing = client.containers.get("mc_mcp_inspector") + existing = client.containers.get("cubbi_mcp_inspector") if existing.status == "running": existing.stop(timeout=1) existing.remove(force=True) @@ -1722,7 +1723,7 @@ exec npm start for mcp in all_mcps: if mcp.get("type") in ["docker", "proxy"]: mcp_name = mcp.get("name") - container_name = f"mc_mcp_{mcp_name}" + container_name = f"cubbi_mcp_{mcp_name}" try: # Check if this container exists @@ -1742,7 +1743,7 @@ exec npm start container = client.containers.run( image="mcp/inspector", - name="mc_mcp_inspector", # Use a fixed name + name="cubbi_mcp_inspector", # Use a fixed name detach=True, network=initial_network, ports={ @@ -1765,8 +1766,8 @@ exec npm start }, entrypoint="/entrypoint.sh", labels={ - "mc.mcp.inspector": "true", - "mc.managed": "true", + "cubbi.mcp.inspector": "true", + "cubbi.managed": "true", }, network_mode=None, # Don't use network_mode as we're using network with aliases networking_config=client.api.create_networking_config(network_config), @@ -1802,7 +1803,7 @@ exec npm start for mcp in all_mcps: if mcp.get("type") in ["docker", "proxy"]: mcp_name = mcp.get("name") - container_name = f"mc_mcp_{mcp_name}" + container_name = f"cubbi_mcp_{mcp_name}" try: # Check if this container exists @@ -1874,7 +1875,7 @@ exec npm start "[yellow]Warning: No MCP servers found or started. The Inspector will run but won't have any servers to connect to.[/yellow]" ) console.print( - "Start MCP servers using 'mc mcp start --all' and then restart the Inspector." + "Start MCP servers using 'cubbi mcp start --all' and then restart the Inspector." ) if not detach: @@ -1890,19 +1891,19 @@ exec npm start def session_create_entry_point(): - """Entry point that directly invokes 'mc session create'. + """Entry point that directly invokes 'cubbi session create'. This provides a convenient shortcut: - - 'mcx' runs as if you typed 'mc session create' - - 'mcx .' mounts the current directory - - 'mcx /path/to/project' mounts the specified directory - - 'mcx repo-url' clones the repository + - 'cubbix' runs as if you typed 'cubbi session create' + - 'cubbix .' mounts the current directory + - 'cubbix /path/to/project' mounts the specified directory + - 'cubbix repo-url' clones the repository All command-line options are passed through to 'session create'. """ import sys - # Save the program name (e.g., 'mcx') + # Save the program name (e.g., 'cubbix') prog_name = sys.argv[0] # Insert 'session' and 'create' commands before any other arguments sys.argv.insert(1, "session") diff --git a/mcontainer/config.py b/cubbi/config.py similarity index 92% rename from mcontainer/config.py rename to cubbi/config.py index a3c5557..2a07c9a 100644 --- a/mcontainer/config.py +++ b/cubbi/config.py @@ -5,11 +5,11 @@ import yaml from .models import Config, Image -DEFAULT_CONFIG_DIR = Path.home() / ".config" / "mc" +DEFAULT_CONFIG_DIR = Path.home() / ".config" / "cubbi" DEFAULT_CONFIG_FILE = DEFAULT_CONFIG_DIR / "config.yaml" -DEFAULT_IMAGES_DIR = Path.home() / ".config" / "mc" / "images" +DEFAULT_IMAGES_DIR = Path.home() / ".config" / "cubbi" / "images" PROJECT_ROOT = Path(__file__).parent.parent -BUILTIN_IMAGES_DIR = Path(__file__).parent / "images" # mcontainer/images +BUILTIN_IMAGES_DIR = Path(__file__).parent / "images" # Dynamically loaded from images directory at runtime DEFAULT_IMAGES = {} @@ -60,7 +60,7 @@ class ConfigManager: config = Config( docker={ "socket": "/var/run/docker.sock", - "network": "mc-network", + "network": "cubbi-network", }, defaults={ "image": "goose", @@ -108,7 +108,7 @@ class ConfigManager: def load_image_from_dir(self, image_dir: Path) -> Optional[Image]: """Load an image configuration from a directory""" # Check for image config file - yaml_path = image_dir / "mc-image.yaml" + yaml_path = image_dir / "cubbi-image.yaml" if not yaml_path.exists(): return None @@ -129,7 +129,7 @@ class ConfigManager: try: # Ensure image field is set if not in YAML if "image" not in image_data: - image_data["image"] = f"monadical/mc-{image_data['name']}:latest" + image_data["image"] = f"monadical/cubbi-{image_data['name']}:latest" image = Image.model_validate(image_data) return image @@ -144,13 +144,13 @@ class ConfigManager: return None def _load_package_images(self) -> Dict[str, Image]: - """Load all package images from the mcontainer/images directory""" + """Load all package images from the cubbi/images directory""" images = {} if not BUILTIN_IMAGES_DIR.exists(): return images - # Search for mc-image.yaml files in each subdirectory + # Search for cubbi-image.yaml files in each subdirectory for image_dir in BUILTIN_IMAGES_DIR.iterdir(): if image_dir.is_dir(): image = self.load_image_from_dir(image_dir) diff --git a/mcontainer/container.py b/cubbi/container.py similarity index 92% rename from mcontainer/container.py rename to cubbi/container.py index a3009d5..2fe156b 100644 --- a/mcontainer/container.py +++ b/cubbi/container.py @@ -42,8 +42,8 @@ class ContainerManager: sys.exit(1) def _ensure_network(self) -> None: - """Ensure the MC network exists""" - network_name = self.config_manager.config.docker.get("network", "mc-network") + """Ensure the Cubbi network exists""" + network_name = self.config_manager.config.docker.get("network", "cubbi-network") networks = self.client.networks.list(names=[network_name]) if not networks: self.client.networks.create(network_name, driver="bridge") @@ -64,8 +64,8 @@ class ContainerManager: Returns: Path to the project configuration directory, or None if no project_name is provided """ - # Get home directory for the MC config - mc_home = pathlib.Path.home() / ".mc" + # Get home directory for the Cubbi config + cubbi_home = pathlib.Path.home() / ".cubbi" # Only use project_name if explicitly provided if project_name: @@ -73,7 +73,7 @@ class ContainerManager: project_hash = hashlib.md5(project_name.encode()).hexdigest() # Create the project config directory path - config_path = mc_home / "projects" / project_hash / "config" + config_path = cubbi_home / "projects" / project_hash / "config" # Create the directory if it doesn't exist config_path.parent.mkdir(parents=True, exist_ok=True) @@ -82,22 +82,22 @@ class ContainerManager: return config_path else: # If no project_name is provided, don't create any config directory - # This ensures we don't mount the /mc-config volume for project-less sessions + # This ensures we don't mount the /cubbi-config volume for project-less sessions return None def list_sessions(self) -> List[Session]: - """List all active MC sessions""" + """List all active Cubbi sessions""" sessions = [] try: containers = self.client.containers.list( - all=True, filters={"label": "mc.session"} + all=True, filters={"label": "cubbi.session"} ) for container in containers: container_id = container.id labels = container.labels - session_id = labels.get("mc.session.id") + session_id = labels.get("cubbi.session.id") if not session_id: continue @@ -109,8 +109,8 @@ class ContainerManager: session = Session( id=session_id, - name=labels.get("mc.session.name", f"mc-{session_id}"), - image=labels.get("mc.image", "unknown"), + name=labels.get("cubbi.session.name", f"cubbi-{session_id}"), + image=labels.get("cubbi.image", "unknown"), status=status, container_id=container_id, ) @@ -153,7 +153,7 @@ class ContainerManager: provider: Optional[str] = None, ssh: bool = False, ) -> Optional[Session]: - """Create a new MC session + """Create a new Cubbi session Args: image_name: The name of the image to use @@ -180,7 +180,7 @@ class ContainerManager: # Generate session ID and name session_id = self._generate_session_id() if not session_name: - session_name = f"mc-{session_id}" + session_name = f"cubbi-{session_id}" # Ensure network exists self._ensure_network() @@ -188,12 +188,12 @@ class ContainerManager: # Prepare environment variables env_vars = environment or {} - # Add MC_USER_ID and MC_GROUP_ID for entrypoint script - env_vars["MC_USER_ID"] = str(uid) if uid is not None else "1000" - env_vars["MC_GROUP_ID"] = str(gid) if gid is not None else "1000" + # Add CUBBI_USER_ID and CUBBI_GROUP_ID for entrypoint script + env_vars["CUBBI_USER_ID"] = str(uid) if uid is not None else "1000" + env_vars["CUBBI_GROUP_ID"] = str(gid) if gid is not None else "1000" # Set SSH environment variable - env_vars["MC_SSH_ENABLED"] = "true" if ssh else "false" + env_vars["CUBBI_SSH_ENABLED"] = "true" if ssh else "false" # Pass API keys from host environment to container for local development api_keys = [ @@ -240,7 +240,7 @@ class ContainerManager: # Clear project for container environment since we're mounting project = None elif is_git_repo: - env_vars["MC_PROJECT_URL"] = project + env_vars["CUBBI_PROJECT_URL"] = project print( f"Git repository URL provided - container will clone {project} into /app during initialization" ) @@ -269,13 +269,13 @@ class ContainerManager: # Mount the project configuration directory session_volumes[str(project_config_path)] = { - "bind": "/mc-config", + "bind": "/cubbi-config", "mode": "rw", } # Add environment variables for config path - env_vars["MC_CONFIG_DIR"] = "/mc-config" - env_vars["MC_IMAGE_CONFIG_DIR"] = f"/mc-config/{image_name}" + env_vars["CUBBI_CONFIG_DIR"] = "/cubbi-config" + env_vars["CUBBI_IMAGE_CONFIG_DIR"] = f"/cubbi-config/{image_name}" # Create image-specific config directories and set up direct volume mounts if image.persistent_configs: @@ -284,7 +284,7 @@ class ContainerManager: for config in image.persistent_configs: # Get target directory path on host target_dir = project_config_path / config.target.removeprefix( - "/mc-config/" + "/cubbi-config/" ) # Create directory if it's a directory type config @@ -299,7 +299,7 @@ class ContainerManager: # File will be created by the container if needed # Store the source and target paths for the init script - # Note: config.target is the path *within* /mc-config + # Note: config.target is the path *within* /cubbi-config persistent_links_data.append(f"{config.source}:{config.target}") print( @@ -308,20 +308,20 @@ class ContainerManager: # Set up persistent links if persistent_links_data: - env_vars["MC_PERSISTENT_LINKS"] = ";".join( + env_vars["CUBBI_PERSISTENT_LINKS"] = ";".join( persistent_links_data ) print( - f"Setting MC_PERSISTENT_LINKS={env_vars['MC_PERSISTENT_LINKS']}" + f"Setting CUBBI_PERSISTENT_LINKS={env_vars['CUBBI_PERSISTENT_LINKS']}" ) else: print( "No project_name provided - skipping configuration directory setup." ) - # Default MC network + # Default Cubbi network default_network = self.config_manager.config.docker.get( - "network", "mc-network" + "network", "cubbi-network" ) # Get network list @@ -440,9 +440,9 @@ class ContainerManager: env_vars["MCP_NAMES"] = json.dumps(mcp_names) # Add user-specified networks - # Default MC network + # Default Cubbi network default_network = self.config_manager.config.docker.get( - "network", "mc-network" + "network", "cubbi-network" ) # Get network list, ensuring default is first and no duplicates @@ -468,12 +468,12 @@ class ContainerManager: target_shell = "/bin/bash" if run_command: - # Set environment variable for mc-init.sh to pick up - env_vars["MC_RUN_COMMAND"] = run_command + # Set environment variable for cubbi-init.sh to pick up + env_vars["CUBBI_RUN_COMMAND"] = run_command # Set the container's command to be the final shell container_command = [target_shell] logger.info( - f"Setting MC_RUN_COMMAND and targeting shell {target_shell}" + f"Setting CUBBI_RUN_COMMAND and targeting shell {target_shell}" ) else: # Use default behavior (often defined by image's ENTRYPOINT/CMD) @@ -486,10 +486,10 @@ class ContainerManager: ) # Set default model/provider from user config if not explicitly provided - env_vars["MC_MODEL"] = model or self.user_config_manager.get( + env_vars["CUBBI_MODEL"] = model or self.user_config_manager.get( "defaults.model", "" ) - env_vars["MC_PROVIDER"] = provider or self.user_config_manager.get( + env_vars["CUBBI_PROVIDER"] = provider or self.user_config_manager.get( "defaults.provider", "" ) @@ -504,13 +504,13 @@ class ContainerManager: environment=env_vars, volumes=session_volumes, labels={ - "mc.session": "true", - "mc.session.id": session_id, - "mc.session.name": session_name, - "mc.image": image_name, - "mc.project": project or "", - "mc.project_name": project_name or "", - "mc.mcps": ",".join(mcp_names) if mcp_names else "", + "cubbi.session": "true", + "cubbi.session.id": session_id, + "cubbi.session.name": session_name, + "cubbi.image": image_name, + "cubbi.project": project or "", + "cubbi.project_name": project_name or "", + "cubbi.mcps": ",".join(mcp_names) if mcp_names else "", }, network=network_list[0], # Connect to the first network initially command=container_command, # Set the command @@ -549,7 +549,7 @@ class ContainerManager: for mcp_name in mcp_names: try: # Get the dedicated network for this MCP - dedicated_network_name = f"mc-mcp-{mcp_name}-network" + dedicated_network_name = f"cubbi-mcp-{mcp_name}-network" try: network = self.client.networks.get(dedicated_network_name) @@ -633,7 +633,7 @@ class ContainerManager: return None def close_session(self, session_id: str) -> bool: - """Close a MC session""" + """Close a Cubbi session""" try: sessions = self.list_sessions() for session in sessions: @@ -648,7 +648,7 @@ class ContainerManager: return False def connect_session(self, session_id: str) -> bool: - """Connect to a running MC session""" + """Connect to a running Cubbi session""" # Retrieve full session data which should include uid/gid session_data = self.session_manager.get_session(session_id) @@ -738,7 +738,7 @@ class ContainerManager: return False def close_all_sessions(self, progress_callback=None) -> Tuple[int, bool]: - """Close all MC sessions with parallel processing and progress reporting + """Close all Cubbi sessions with parallel processing and progress reporting Args: progress_callback: Optional callback function to report progress @@ -811,7 +811,7 @@ class ContainerManager: return 0, False def get_session_logs(self, session_id: str, follow: bool = False) -> Optional[str]: - """Get logs from a MC session""" + """Get logs from a Cubbi session""" try: sessions = self.list_sessions() for session in sessions: @@ -832,7 +832,7 @@ class ContainerManager: return None def get_init_logs(self, session_id: str, follow: bool = False) -> Optional[str]: - """Get initialization logs from a MC session + """Get initialization logs from a Cubbi session Args: session_id: The session ID diff --git a/mcontainer/mc_inspector_entrypoint.sh b/cubbi/cubbi_inspector_entrypoint.sh similarity index 100% rename from mcontainer/mc_inspector_entrypoint.sh rename to cubbi/cubbi_inspector_entrypoint.sh diff --git a/mcontainer/images/__init__.py b/cubbi/images/__init__.py similarity index 100% rename from mcontainer/images/__init__.py rename to cubbi/images/__init__.py diff --git a/mcontainer/images/base.py b/cubbi/images/base.py similarity index 100% rename from mcontainer/images/base.py rename to cubbi/images/base.py diff --git a/mcontainer/images/goose/Dockerfile b/cubbi/images/goose/Dockerfile similarity index 88% rename from mcontainer/images/goose/Dockerfile rename to cubbi/images/goose/Dockerfile index 21f9356..0aca51f 100644 --- a/mcontainer/images/goose/Dockerfile +++ b/cubbi/images/goose/Dockerfile @@ -1,7 +1,7 @@ FROM python:3.12-slim LABEL maintainer="team@monadical.com" -LABEL description="Goose with MCP servers" +LABEL description="Goose with MCP servers for Cubbi" # Install system dependencies including gosu for user switching and shadow for useradd/groupadd RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -41,16 +41,16 @@ RUN curl -fsSL https://github.com/block/goose/releases/download/stable/download_ WORKDIR /app # Copy initialization scripts -COPY mc-init.sh /mc-init.sh +COPY cubbi-init.sh /cubbi-init.sh COPY entrypoint.sh /entrypoint.sh -COPY mc-image.yaml /mc-image.yaml +COPY cubbi-image.yaml /cubbi-image.yaml COPY init-status.sh /init-status.sh COPY update-goose-config.py /usr/local/bin/update-goose-config.py # Extend env via bashrc # Make scripts executable -RUN chmod +x /mc-init.sh /entrypoint.sh /init-status.sh \ +RUN chmod +x /cubbi-init.sh /entrypoint.sh /init-status.sh \ /usr/local/bin/update-goose-config.py # Set up initialization status check on login @@ -59,7 +59,7 @@ RUN echo '[ -x /init-status.sh ] && /init-status.sh' >> /etc/bash.bashrc # Set up environment ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 -# Set WORKDIR to /app, common practice and expected by mc-init.sh +# Set WORKDIR to /app, common practice and expected by cubbi-init.sh WORKDIR /app # Expose ports diff --git a/mcontainer/images/goose/README.md b/cubbi/images/goose/README.md similarity index 68% rename from mcontainer/images/goose/README.md rename to cubbi/images/goose/README.md index d0f7b4a..8bdfba5 100644 --- a/mcontainer/images/goose/README.md +++ b/cubbi/images/goose/README.md @@ -17,9 +17,9 @@ This image provides a containerized environment for running [Goose](https://goos | `LANGFUSE_INIT_PROJECT_PUBLIC_KEY` | Langfuse public key | No | | `LANGFUSE_INIT_PROJECT_SECRET_KEY` | Langfuse secret key | No | | `LANGFUSE_URL` | Langfuse API URL | No | -| `MC_PROJECT_URL` | Project repository URL | No | -| `MC_GIT_SSH_KEY` | SSH key for Git authentication | No | -| `MC_GIT_TOKEN` | Token for Git authentication | No | +| `CUBBI_PROJECT_URL` | Project repository URL | No | +| `CUBBI_GIT_SSH_KEY` | SSH key for Git authentication | No | +| `CUBBI_GIT_TOKEN` | Token for Git authentication | No | ## Build @@ -27,15 +27,15 @@ To build this image: ```bash cd drivers/goose -docker build -t monadical/mc-goose:latest . +docker build -t monadical/cubbi-goose:latest . ``` ## Usage ```bash # Create a new session with this image -mc session create --driver goose +cubbi session create --driver goose # Create with project repository -mc session create --driver goose --project github.com/username/repo +cubbi session create --driver goose --project github.com/username/repo ``` diff --git a/mcontainer/images/goose/mc-image.yaml b/cubbi/images/goose/cubbi-image.yaml similarity index 76% rename from mcontainer/images/goose/mc-image.yaml rename to cubbi/images/goose/cubbi-image.yaml index f84e27f..5be3d3d 100644 --- a/mcontainer/images/goose/mc-image.yaml +++ b/cubbi/images/goose/cubbi-image.yaml @@ -2,10 +2,10 @@ name: goose description: Goose AI environment version: 1.0.0 maintainer: team@monadical.com -image: monadical/mc-goose:latest +image: monadical/cubbi-goose:latest init: - pre_command: /mc-init.sh + pre_command: /cubbi-init.sh command: /entrypoint.sh environment: @@ -25,21 +25,21 @@ environment: default: https://cloud.langfuse.com # Project environment variables - - name: MC_PROJECT_URL + - name: CUBBI_PROJECT_URL description: Project repository URL required: false - - name: MC_PROJECT_TYPE + - name: CUBBI_PROJECT_TYPE description: Project repository type (git, svn, etc.) required: false default: git - - name: MC_GIT_SSH_KEY + - name: CUBBI_GIT_SSH_KEY description: SSH key for Git authentication required: false sensitive: true - - name: MC_GIT_TOKEN + - name: CUBBI_GIT_TOKEN description: Token for Git authentication required: false sensitive: true @@ -54,10 +54,10 @@ volumes: persistent_configs: - source: "/app/.goose" - target: "/mc-config/goose-app" + target: "/cubbi-config/goose-app" type: "directory" description: "Goose memory" - - source: "/home/mcuser/.config/goose" - target: "/mc-config/goose-config" + - source: "/home/cubbi/.config/goose" + target: "/cubbi-config/goose-config" type: "directory" - description: "Goose configuration" \ No newline at end of file + description: "Goose configuration" diff --git a/mcontainer/images/goose/mc-init.sh b/cubbi/images/goose/cubbi-init.sh similarity index 53% rename from mcontainer/images/goose/mc-init.sh rename to cubbi/images/goose/cubbi-init.sh index cdadf70..b6b6a10 100755 --- a/mcontainer/images/goose/mc-init.sh +++ b/cubbi/images/goose/cubbi-init.sh @@ -1,59 +1,59 @@ #!/bin/bash -# Standardized initialization script for MC images +# Standardized initialization script for Cubbi images # Redirect all output to both stdout and the log file exec > >(tee -a /init.log) 2>&1 # Mark initialization as started -echo "=== MC Initialization started at $(date) ===" +echo "=== Cubbi Initialization started at $(date) ===" # --- START INSERTED BLOCK --- -# Default UID/GID if not provided (should be passed by mc tool) -MC_USER_ID=${MC_USER_ID:-1000} -MC_GROUP_ID=${MC_GROUP_ID:-1000} +# Default UID/GID if not provided (should be passed by cubbi tool) +CUBBI_USER_ID=${CUBBI_USER_ID:-1000} +CUBBI_GROUP_ID=${CUBBI_GROUP_ID:-1000} -echo "Using UID: $MC_USER_ID, GID: $MC_GROUP_ID" +echo "Using UID: $CUBBI_USER_ID, GID: $CUBBI_GROUP_ID" # Create group if it doesn't exist -if ! getent group mcuser > /dev/null; then - groupadd -g $MC_GROUP_ID mcuser +if ! getent group cubbi > /dev/null; then + groupadd -g $CUBBI_GROUP_ID cubbi else # If group exists but has different GID, modify it - EXISTING_GID=$(getent group mcuser | cut -d: -f3) - if [ "$EXISTING_GID" != "$MC_GROUP_ID" ]; then - groupmod -g $MC_GROUP_ID mcuser + EXISTING_GID=$(getent group cubbi | cut -d: -f3) + if [ "$EXISTING_GID" != "$CUBBI_GROUP_ID" ]; then + groupmod -g $CUBBI_GROUP_ID cubbi fi fi # Create user if it doesn't exist -if ! getent passwd mcuser > /dev/null; then - useradd --shell /bin/bash --uid $MC_USER_ID --gid $MC_GROUP_ID --no-create-home mcuser +if ! getent passwd cubbi > /dev/null; then + useradd --shell /bin/bash --uid $CUBBI_USER_ID --gid $CUBBI_GROUP_ID --no-create-home cubbi else # If user exists but has different UID/GID, modify it - EXISTING_UID=$(getent passwd mcuser | cut -d: -f3) - EXISTING_GID=$(getent passwd mcuser | cut -d: -f4) - if [ "$EXISTING_UID" != "$MC_USER_ID" ] || [ "$EXISTING_GID" != "$MC_GROUP_ID" ]; then - usermod --uid $MC_USER_ID --gid $MC_GROUP_ID mcuser + EXISTING_UID=$(getent passwd cubbi | cut -d: -f3) + EXISTING_GID=$(getent passwd cubbi | cut -d: -f4) + if [ "$EXISTING_UID" != "$CUBBI_USER_ID" ] || [ "$EXISTING_GID" != "$CUBBI_GROUP_ID" ]; then + usermod --uid $CUBBI_USER_ID --gid $CUBBI_GROUP_ID cubbi fi fi # Create home directory and set permissions -mkdir -p /home/mcuser -chown $MC_USER_ID:$MC_GROUP_ID /home/mcuser +mkdir -p /home/cubbi +chown $CUBBI_USER_ID:$CUBBI_GROUP_ID /home/cubbi mkdir -p /app -chown $MC_USER_ID:$MC_GROUP_ID /app +chown $CUBBI_USER_ID:$CUBBI_GROUP_ID /app # Copy /root/.local/bin to the user's home directory if [ -d /root/.local/bin ]; then - echo "Copying /root/.local/bin to /home/mcuser/.local/bin..." - mkdir -p /home/mcuser/.local/bin - cp -r /root/.local/bin/* /home/mcuser/.local/bin/ - chown -R $MC_USER_ID:$MC_GROUP_ID /home/mcuser/.local + echo "Copying /root/.local/bin to /home/cubbi/.local/bin..." + mkdir -p /home/cubbi/.local/bin + cp -r /root/.local/bin/* /home/cubbi/.local/bin/ + chown -R $CUBBI_USER_ID:$CUBBI_GROUP_ID /home/cubbi/.local fi # Start SSH server only if explicitly enabled -if [ "$MC_SSH_ENABLED" = "true" ]; then +if [ "$CUBBI_SSH_ENABLED" = "true" ]; then echo "Starting SSH server..." /usr/sbin/sshd else @@ -65,13 +65,13 @@ fi echo "INIT_COMPLETE=false" > /init.status # Project initialization -if [ -n "$MC_PROJECT_URL" ]; then - echo "Initializing project: $MC_PROJECT_URL" +if [ -n "$CUBBI_PROJECT_URL" ]; then + echo "Initializing project: $CUBBI_PROJECT_URL" # Set up SSH key if provided - if [ -n "$MC_GIT_SSH_KEY" ]; then + if [ -n "$CUBBI_GIT_SSH_KEY" ]; then mkdir -p ~/.ssh - echo "$MC_GIT_SSH_KEY" > ~/.ssh/id_ed25519 + echo "$CUBBI_GIT_SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null ssh-keyscan gitlab.com >> ~/.ssh/known_hosts 2>/dev/null @@ -79,23 +79,23 @@ if [ -n "$MC_PROJECT_URL" ]; then fi # Set up token if provided - if [ -n "$MC_GIT_TOKEN" ]; then + if [ -n "$CUBBI_GIT_TOKEN" ]; then git config --global credential.helper store - echo "https://$MC_GIT_TOKEN:x-oauth-basic@github.com" > ~/.git-credentials + echo "https://$CUBBI_GIT_TOKEN:x-oauth-basic@github.com" > ~/.git-credentials fi # Clone repository - git clone $MC_PROJECT_URL /app + git clone $CUBBI_PROJECT_URL /app cd /app # Run project-specific initialization if present - if [ -f "/app/.mc/init.sh" ]; then - bash /app/.mc/init.sh + if [ -f "/app/.cubbi/init.sh" ]; then + bash /app/.cubbi/init.sh fi # Persistent configs are now directly mounted as volumes # No need to create symlinks anymore - if [ -n "$MC_CONFIG_DIR" ] && [ -d "$MC_CONFIG_DIR" ]; then + if [ -n "$CUBBI_CONFIG_DIR" ] && [ -d "$CUBBI_CONFIG_DIR" ]; then echo "Using persistent configuration volumes (direct mounts)" fi fi @@ -110,18 +110,18 @@ if [ -n "$LANGFUSE_INIT_PROJECT_SECRET_KEY" ] && [ -n "$LANGFUSE_INIT_PROJECT_PU export LANGFUSE_URL="${LANGFUSE_URL:-https://cloud.langfuse.com}" fi -# Ensure /mc-config directory exists (required for symlinks) -if [ ! -d "/mc-config" ]; then - echo "Creating /mc-config directory since it doesn't exist" - mkdir -p /mc-config - chown $MC_USER_ID:$MC_GROUP_ID /mc-config +# Ensure /cubbi-config directory exists (required for symlinks) +if [ ! -d "/cubbi-config" ]; then + echo "Creating /cubbi-config directory since it doesn't exist" + mkdir -p /cubbi-config + chown $CUBBI_USER_ID:$CUBBI_GROUP_ID /cubbi-config fi # Create symlinks for persistent configurations defined in the image -if [ -n "$MC_PERSISTENT_LINKS" ]; then +if [ -n "$CUBBI_PERSISTENT_LINKS" ]; then echo "Creating persistent configuration symlinks..." # Split by semicolon - IFS=';' read -ra LINKS <<< "$MC_PERSISTENT_LINKS" + IFS=';' read -ra LINKS <<< "$CUBBI_PERSISTENT_LINKS" for link_pair in "${LINKS[@]}"; do # Split by colon IFS=':' read -r source_path target_path <<< "$link_pair" @@ -134,47 +134,46 @@ if [ -n "$MC_PERSISTENT_LINKS" ]; then echo "Processing link: $source_path -> $target_path" parent_dir=$(dirname "$source_path") - # Ensure parent directory of the link source exists and is owned by mcuser + # Ensure parent directory of the link source exists and is owned by cubbi if [ ! -d "$parent_dir" ]; then echo "Creating parent directory: $parent_dir" mkdir -p "$parent_dir" - echo "Changing ownership of parent $parent_dir to $MC_USER_ID:$MC_GROUP_ID" - chown "$MC_USER_ID:$MC_GROUP_ID" "$parent_dir" || echo "Warning: Could not chown parent $parent_dir" + echo "Changing ownership of parent $parent_dir to $CUBBI_USER_ID:$CUBBI_GROUP_ID" + chown "$CUBBI_USER_ID:$CUBBI_GROUP_ID" "$parent_dir" || echo "Warning: Could not chown parent $parent_dir" fi # Create the symlink (force, no-dereference) echo "Creating symlink: ln -sfn $target_path $source_path" ln -sfn "$target_path" "$source_path" - # Optionally, change ownership of the symlink itself - echo "Changing ownership of symlink $source_path to $MC_USER_ID:$MC_GROUP_ID" - chown -h "$MC_USER_ID:$MC_GROUP_ID" "$source_path" || echo "Warning: Could not chown symlink $source_path" + echo "Changing ownership of symlink $source_path to $CUBBI_USER_ID:$CUBBI_GROUP_ID" + chown -h "$CUBBI_USER_ID:$CUBBI_GROUP_ID" "$source_path" || echo "Warning: Could not chown symlink $source_path" done echo "Persistent configuration symlinks created." fi -# Update Goose configuration with available MCP servers (run as mcuser after symlinks are created) +# Update Goose configuration with available MCP servers (run as cubbi after symlinks are created) if [ -f "/usr/local/bin/update-goose-config.py" ]; then - echo "Updating Goose configuration with MCP servers as mcuser..." - gosu mcuser /usr/local/bin/update-goose-config.py + echo "Updating Goose configuration with MCP servers as cubbi..." + gosu cubbi /usr/local/bin/update-goose-config.py elif [ -f "$(dirname "$0")/update-goose-config.py" ]; then - echo "Updating Goose configuration with MCP servers as mcuser..." - gosu mcuser "$(dirname "$0")/update-goose-config.py" + echo "Updating Goose configuration with MCP servers as cubbi..." + gosu cubbi "$(dirname "$0")/update-goose-config.py" else echo "Warning: update-goose-config.py script not found. Goose configuration will not be updated." fi -# Run the user command first, if set, as mcuser -if [ -n "$MC_RUN_COMMAND" ]; then - echo "--- Executing initial command: $MC_RUN_COMMAND ---"; - gosu mcuser sh -c "$MC_RUN_COMMAND"; # Run user command as mcuser +# Run the user command first, if set, as cubbi +if [ -n "$CUBBI_RUN_COMMAND" ]; then + echo "--- Executing initial command: $CUBBI_RUN_COMMAND ---"; + gosu cubbi sh -c "$CUBBI_RUN_COMMAND"; # Run user command as cubbi COMMAND_EXIT_CODE=$?; echo "--- Initial command finished (exit code: $COMMAND_EXIT_CODE) ---"; fi; # Mark initialization as complete -echo "=== MC Initialization completed at $(date) ===" +echo "=== Cubbi Initialization completed at $(date) ===" echo "INIT_COMPLETE=true" > /init.status -exec gosu mcuser "$@" +exec gosu cubbi "$@" diff --git a/mcontainer/images/goose/entrypoint.sh b/cubbi/images/goose/entrypoint.sh similarity index 90% rename from mcontainer/images/goose/entrypoint.sh rename to cubbi/images/goose/entrypoint.sh index 9ddc95f..96d89b0 100755 --- a/mcontainer/images/goose/entrypoint.sh +++ b/cubbi/images/goose/entrypoint.sh @@ -4,4 +4,4 @@ # service startup (like sshd), and switching to the non-root user # before running the container's command (CMD). -exec /mc-init.sh "$@" +exec /cubbi-init.sh "$@" diff --git a/mcontainer/images/goose/init-status.sh b/cubbi/images/goose/init-status.sh similarity index 96% rename from mcontainer/images/goose/init-status.sh rename to cubbi/images/goose/init-status.sh index 4efda67..031ba4b 100644 --- a/mcontainer/images/goose/init-status.sh +++ b/cubbi/images/goose/init-status.sh @@ -28,4 +28,4 @@ if ! grep -q "INIT_COMPLETE=true" "/init.status" 2>/dev/null; then fi fi -exec gosu mcuser /bin/bash -il +exec gosu cubbi /bin/bash -il diff --git a/mcontainer/images/goose/update-goose-config.py b/cubbi/images/goose/update-goose-config.py similarity index 97% rename from mcontainer/images/goose/update-goose-config.py rename to cubbi/images/goose/update-goose-config.py index 5a7ccc3..e485d45 100644 --- a/mcontainer/images/goose/update-goose-config.py +++ b/cubbi/images/goose/update-goose-config.py @@ -39,8 +39,8 @@ def update_config(): } # Update goose configuration with model and provider from environment variables - goose_model = os.environ.get("MC_MODEL") - goose_provider = os.environ.get("MC_PROVIDER") + goose_model = os.environ.get("CUBBI_MODEL") + goose_provider = os.environ.get("CUBBI_PROVIDER") if goose_model: config_data["GOOSE_MODEL"] = goose_model diff --git a/mcontainer/mcp.py b/cubbi/mcp.py similarity index 97% rename from mcontainer/mcp.py rename to cubbi/mcp.py index 1a89fab..3526811 100644 --- a/mcontainer/mcp.py +++ b/cubbi/mcp.py @@ -1,5 +1,5 @@ """ -MCP (Model Control Protocol) server management for Monadical Container. +MCP (Model Control Protocol) server management for Cubbi Container. """ import logging @@ -38,7 +38,7 @@ class MCPManager: """Ensure the MCP network exists and return its name. Note: This is used only by the inspector, not for session-to-MCP connections. """ - network_name = "mc-mcp-network" + network_name = "cubbi-mcp-network" if self.client: networks = self.client.networks.list(names=[network_name]) if not networks: @@ -54,7 +54,7 @@ class MCPManager: Returns: The name of the dedicated network """ - network_name = f"mc-mcp-{mcp_name}-network" + network_name = f"cubbi-mcp-{mcp_name}-network" if self.client: networks = self.client.networks.list(names=[network_name]) if not networks: @@ -282,7 +282,7 @@ class MCPManager: def get_mcp_container_name(self, mcp_name: str) -> str: """Get the Docker container name for an MCP server.""" - return f"mc_mcp_{mcp_name}" + return f"cubbi_mcp_{mcp_name}" def start_mcp(self, name: str) -> Dict[str, Any]: """Start an MCP server container.""" @@ -374,9 +374,9 @@ class MCPManager: network=None, # Start without network, we'll add it with aliases environment=mcp_config.get("env", {}), labels={ - "mc.mcp": "true", - "mc.mcp.name": name, - "mc.mcp.type": "docker", + "cubbi.mcp": "true", + "cubbi.mcp.name": name, + "cubbi.mcp.type": "docker", }, ) @@ -540,7 +540,7 @@ ENTRYPOINT ["/entrypoint.sh"] f.write(dockerfile_content) # Build the image - custom_image_name = f"mc_mcp_proxy_{name}" + custom_image_name = f"cubbi_mcp_proxy_{name}" logger.info(f"Building custom proxy image: {custom_image_name}") self.client.images.build( path=tmp_dir, @@ -577,9 +577,9 @@ ENTRYPOINT ["/entrypoint.sh"] } }, labels={ - "mc.mcp": "true", - "mc.mcp.name": name, - "mc.mcp.type": "proxy", + "cubbi.mcp": "true", + "cubbi.mcp.name": name, + "cubbi.mcp.type": "proxy", }, ports=port_bindings, # Bind the SSE port to the host if configured ) @@ -816,8 +816,10 @@ ENTRYPOINT ["/entrypoint.sh"] if not self.client: raise Exception("Docker client is not available") - # Get all containers with the mc.mcp label - containers = self.client.containers.list(all=True, filters={"label": "mc.mcp"}) + # Get all containers with the cubbi.mcp label + containers = self.client.containers.list( + all=True, filters={"label": "cubbi.mcp"} + ) result = [] for container in containers: @@ -858,13 +860,13 @@ ENTRYPOINT ["/entrypoint.sh"] # Create MCPContainer object mcp_container = MCPContainer( - name=labels.get("mc.mcp.name", "unknown"), + name=labels.get("cubbi.mcp.name", "unknown"), container_id=container.id, status=status, image=container_info["Config"]["Image"], ports=ports, created_at=container_info["Created"], - type=labels.get("mc.mcp.type", "unknown"), + type=labels.get("cubbi.mcp.type", "unknown"), ) result.append(mcp_container) diff --git a/mcontainer/models.py b/cubbi/models.py similarity index 100% rename from mcontainer/models.py rename to cubbi/models.py diff --git a/mcontainer/session.py b/cubbi/session.py similarity index 92% rename from mcontainer/session.py rename to cubbi/session.py index 3dfcc97..b459102 100644 --- a/mcontainer/session.py +++ b/cubbi/session.py @@ -1,5 +1,5 @@ """ -Session storage management for Monadical Container Tool. +Session storage management for Cubbi Container Tool. """ import os @@ -8,7 +8,7 @@ from typing import Dict, Optional import yaml -DEFAULT_SESSIONS_FILE = Path.home() / ".config" / "mc" / "sessions.yaml" +DEFAULT_SESSIONS_FILE = Path.home() / ".config" / "cubbi" / "sessions.yaml" class SessionManager: @@ -19,7 +19,7 @@ class SessionManager: Args: sessions_path: Optional path to the sessions file. - Defaults to ~/.config/mc/sessions.yaml. + Defaults to ~/.config/cubbi/sessions.yaml. """ self.sessions_path = sessions_path or DEFAULT_SESSIONS_FILE self.sessions = self._load_sessions() diff --git a/mcontainer/user_config.py b/cubbi/user_config.py similarity index 97% rename from mcontainer/user_config.py rename to cubbi/user_config.py index f1f8957..70718c1 100644 --- a/mcontainer/user_config.py +++ b/cubbi/user_config.py @@ -1,5 +1,5 @@ """ -User configuration manager for Monadical Container Tool. +User configuration manager for Cubbi Container Tool. """ import os @@ -28,11 +28,11 @@ class UserConfigManager: Args: config_path: Optional path to the configuration file. - Defaults to ~/.config/mc/config.yaml. + Defaults to ~/.config/cubbi/config.yaml. """ - # Default to ~/.config/mc/config.yaml + # Default to ~/.config/cubbi/config.yaml self.config_path = Path( - config_path or os.path.expanduser("~/.config/mc/config.yaml") + config_path or os.path.expanduser("~/.config/cubbi/config.yaml") ) self.config = self._load_config() @@ -93,7 +93,7 @@ class UserConfigManager: "image": "goose", "connect": True, "mount_local": True, - "networks": [], # Default networks to connect to (besides mc-network) + "networks": [], # Default networks to connect to (besides cubbi-network) "volumes": [], # Default volumes to mount, format: "source:dest" "mcps": [], # Default MCP servers to connect to "model": "claude-3-5-sonnet-latest", # Default LLM model to use @@ -107,7 +107,7 @@ class UserConfigManager: "google": {}, }, "docker": { - "network": "mc-network", + "network": "cubbi-network", }, "ui": { "colors": True, diff --git a/mcontainer/utils/git.py b/cubbi/utils/git.py similarity index 100% rename from mcontainer/utils/git.py rename to cubbi/utils/git.py diff --git a/docs/specs/1_SPECIFICATIONS.md b/docs/specs/1_SPECIFICATIONS.md index b231687..9dff1f8 100644 --- a/docs/specs/1_SPECIFICATIONS.md +++ b/docs/specs/1_SPECIFICATIONS.md @@ -1,22 +1,22 @@ -# MC - Monadical AI Container Tool +# Cubbi - Container Tool ## Overview -MC (Monadical Container) is a command-line tool for managing ephemeral +Cubbi is a command-line tool for managing ephemeral containers that run AI tools and development environments. It works with both local Docker and a dedicated remote web service that manages containers in a Docker-in-Docker (DinD) environment. ## Technology Stack -### MC Service +### Cubbi Service - **Web Framework**: FastAPI for high-performance, async API endpoints - **Package Management**: uv (Astral) for dependency management - **Database**: SQLite for development, PostgreSQL for production - **Container Management**: Docker SDK for Python - **Authentication**: OAuth 2.0 integration with Authentik -### MC CLI +### Cubbi CLI - **Language**: Python - **Package Management**: uv for dependency management - **Distribution**: Standalone binary via PyInstaller or similar @@ -26,8 +26,8 @@ Docker-in-Docker (DinD) environment. ### Components -1. **CLI Tool (`mc`)**: The command-line interface users interact with -2. **MC Service**: A web service that handles remote container execution +1. **CLI Tool (`cubbi`)**: The command-line interface users interact with +2. **Cubbi Service**: A web service that handles remote container execution 3. **Container Images**: Predefined container templates for various AI tools ### Architecture Diagram @@ -35,8 +35,8 @@ Docker-in-Docker (DinD) environment. ``` ┌─────────────┐ ┌─────────────────────────┐ │ │ │ │ -│ MC CLI │◄─────────►│ Local Docker Daemon │ -│ (mc) │ │ │ +│ Cubbi CLI │◄─────────►│ Local Docker Daemon │ +│ (cubbi) │ │ │ │ │ └─────────────────────────┘ └──────┬──────┘ │ @@ -44,8 +44,8 @@ Docker-in-Docker (DinD) environment. │ ┌──────▼──────┐ ┌─────────────────────────┐ │ │ │ │ -│ MC Service │◄─────────►│ Docker-in-Docker │ -│ (Web API) │ │ │ +│ Cubbi │◄─────────►│ Docker-in-Docker │ +│ Service │ │ │ │ │ └─────────────────────────┘ └─────────────┘ │ @@ -63,21 +63,21 @@ Docker-in-Docker (DinD) environment. - **Session**: An active container instance with a specific image - **Image**: A predefined container template with specific AI tools installed -- **Remote**: A configured MC service instance +- **Remote**: A configured cubbi service instance ## User Configuration -MC supports user-specific configuration via a YAML file located at `~/.config/mc/config.yaml`. This provides a way to set default values, store service credentials, and customize behavior without modifying code. +Cubbi supports user-specific configuration via a YAML file located at `~/.config/cubbi/config.yaml`. This provides a way to set default values, store service credentials, and customize behavior without modifying code. ### Configuration File Structure ```yaml -# ~/.config/mc/config.yaml +# ~/.config/cubbi/config.yaml defaults: image: "goose" # Default image to use connect: true # Automatically connect after creating session mount_local: true # Mount local directory by default - networks: [] # Default networks to connect to (besides mc-network) + networks: [] # Default networks to connect to (besides cubbi-network) services: # Service credentials with simplified naming @@ -97,17 +97,17 @@ services: api_key: "sk-or-..." docker: - network: "mc-network" # Default Docker network to use + network: "cubbi-network" # Default Docker network to use socket: "/var/run/docker.sock" # Docker socket path remote: default: "production" # Default remote to use endpoints: production: - url: "https://mc.monadical.com" + url: "https://cubbi.monadical.com" auth_method: "oauth" staging: - url: "https://mc-staging.monadical.com" + url: "https://cubbi-staging.monadical.com" auth_method: "oauth" ui: @@ -145,22 +145,22 @@ The simplified configuration names are mapped to environment variables: ```bash # View entire configuration -mc config list +cubbi config list # Get specific configuration value -mc config get defaults.driver +cubbi config get defaults.driver # Set configuration value (using simplified naming) -mc config set langfuse.url "https://cloud.langfuse.com" -mc config set openai.api_key "sk-..." +cubbi config set langfuse.url "https://cloud.langfuse.com" +cubbi config set openai.api_key "sk-..." # Network configuration -mc config network list # List default networks -mc config network add example-network # Add a network to defaults -mc config network remove example-network # Remove a network from defaults +cubbi config network list # List default networks +cubbi config network add example-network # Add a network to defaults +cubbi config network remove example-network # Remove a network from defaults # Reset configuration to defaults -mc config reset +cubbi config reset ``` ## CLI Tool Commands @@ -169,81 +169,81 @@ mc config reset ```bash # Create a new session locally (shorthand) -mc +cubbi # List active sessions on local system -mc session list +cubbi session list # Create a new session locally -mc session create [OPTIONS] +cubbi session create [OPTIONS] # Create a session with a specific image -mc session create --image goose +cubbi session create --image goose # Create a session with a specific project repository -mc session create --image goose --project github.com/hello/private +cubbi session create --image goose --project github.com/hello/private # Create a session with external networks -mc session create --network teamnet --network othernetwork +cubbi session create --network teamnet --network othernetwork # Create a session with a project (shorthand) -mc git@github.com:hello/private +cubbi git@github.com:hello/private # Close a specific session -mc session close +cubbi session close # Connect to an existing session -mc session connect +cubbi session connect ``` ### Remote Management ```bash -# Add a remote MC service -mc remote add +# Add a remote Cubbi service +cubbi remote add # List configured remote services -mc remote list +cubbi remote list # Remove a remote service -mc remote remove +cubbi remote remove # Authenticate with a remote service -mc -r auth +cubbi -r auth # Create a session on a remote service -mc -r [session create] +cubbi -r [session create] # List sessions on a remote service -mc -r session list +cubbi -r session list ``` ### Environment Variables ```bash # Set environment variables for a session -mc session create -e VAR1=value1 -e VAR2=value2 +cubbi session create -e VAR1=value1 -e VAR2=value2 # Set environment variables for a remote session -mc -r session create -e VAR1=value1 +cubbi -r session create -e VAR1=value1 ``` ### Logging ```bash # Stream logs from a session -mc session logs +cubbi session logs # Stream logs with follow option -mc session logs -f +cubbi session logs -f ``` -## MC Service Specification +## Cubbi Service Specification ### Overview -The MC Service is a web service that manages ephemeral containers in a Docker-in-Docker environment. It provides a REST API for container lifecycle management, authentication, and real-time log streaming. +The Cubbi Service is a web service that manages ephemeral containers in a Docker-in-Docker environment. It provides a REST API for container lifecycle management, authentication, and real-time log streaming. ### API Endpoints @@ -258,19 +258,19 @@ POST /auth/logout - Invalidate current token ### Authentik Integration -The MC Service integrates with Authentik at https://authentik.monadical.io using OAuth 2.0: +The Cubbi Service integrates with Authentik at https://authentik.monadical.io using OAuth 2.0: 1. **Application Registration**: - - MC Service is registered as an OAuth application in Authentik + - Cubbi Service is registered as an OAuth application in Authentik - Configured with redirect URI to `/auth/callback` - Assigned appropriate scopes for user identification 2. **Authentication Flow**: - User initiates authentication via CLI - - MC CLI opens browser to Authentik authorization URL + - Cubbi CLI opens browser to Authentik authorization URL - User logs in through Authentik's interface - Authentik redirects to callback URL with authorization code - - MC Service exchanges code for access and refresh tokens + - Cubbi Service exchanges code for access and refresh tokens - CLI receives and securely stores tokens 3. **Token Management**: @@ -309,19 +309,19 @@ DELETE /projects/{id} - Remove a project ### Service Configuration ```yaml -# mc-service.yaml +# cubbi-service.yaml server: port: 3000 host: 0.0.0.0 docker: socket: /var/run/docker.sock - network: mc-network + network: cubbi-network auth: provider: authentik url: https://authentik.monadical.io - clientId: mc-service + clientId: cubbi-service logging: providers: @@ -334,11 +334,11 @@ logging: images: - name: goose - image: monadical/mc-goose:latest + image: monadical/cubbi-goose:latest - name: aider - image: monadical/mc-aider:latest + image: monadical/cubbi-aider:latest - name: claude-code - image: monadical/mc-claude-code:latest + image: monadical/cubbi-claude-code:latest projects: storage: @@ -352,7 +352,7 @@ projects: ### Docker-in-Docker Implementation -The MC Service runs in a container with access to the host's Docker socket, allowing it to create and manage sibling containers. This approach provides: +The Cubbi Service runs in a container with access to the host's Docker socket, allowing it to create and manage sibling containers. This approach provides: 1. Isolation between containers 2. Simple lifecycle management @@ -367,7 +367,7 @@ For remote connections to containers, the service provides two methods: ### Logging Implementation -The MC Service implements log collection and forwarding: +The Cubbi Service implements log collection and forwarding: 1. Container logs are captured using Docker's logging drivers 2. Logs are forwarded to configured providers (Fluentd, Langfuse) @@ -377,22 +377,22 @@ The MC Service implements log collection and forwarding: ### Persistent Project Configuration -MC provides persistent storage for project-specific configurations that need to survive container restarts. This is implemented through a dedicated volume mount and symlink system: +Cubbi provides persistent storage for project-specific configurations that need to survive container restarts. This is implemented through a dedicated volume mount and symlink system: 1. **Configuration Storage**: - - Each project has a dedicated configuration directory on the host at `~/.mc/projects//config` + - Each project has a dedicated configuration directory on the host at `~/.cubbi/projects//config` - For projects specified by URL, the hash is derived from the repository URL - For local projects, the hash is derived from the absolute path of the local directory - - This directory is mounted into the container at `/mc-config` + - This directory is mounted into the container at `/cubbi-config` 2. **Image Configuration**: - Each image can specify configuration files/directories that should persist across sessions - - These are defined in the image's `mc-image.yaml` file in the `persistent_configs` section + - These are defined in the image's `cubbi-image.yaml` file in the `persistent_configs` section - Example for Goose image: ```yaml persistent_configs: - source: "/app/.goose" # Path in container - target: "/mc-config/goose" # Path in persistent storage + target: "/cubbi-config/goose" # Path in persistent storage type: "directory" # directory or file description: "Goose memory and configuration" ``` @@ -406,8 +406,8 @@ MC provides persistent storage for project-specific configurations that need to 4. **Environment Variables**: - Container has access to configuration location via environment variables: ``` - MC_CONFIG_DIR=/mc-config - MC_IMAGE_CONFIG_DIR=/mc-config/ + CUBBI_CONFIG_DIR=/cubbi-config + CUBBI_IMAGE_CONFIG_DIR=/cubbi-config/ ``` This ensures that important configurations like Goose's memory store, authentication tokens, and other state information persist between container sessions while maintaining isolation between different projects. @@ -418,21 +418,21 @@ Users can add projects with associated credentials: ```bash # Add a project with SSH key -mc project add github.com/hello/private --ssh-key ~/.ssh/id_ed25519 +cubbi project add github.com/hello/private --ssh-key ~/.ssh/id_ed25519 # Add a project with token authentication -mc project add github.com/hello/private --token ghp_123456789 +cubbi project add github.com/hello/private --token ghp_123456789 # List all projects -mc project list +cubbi project list # Remove a project -mc project remove github.com/hello/private +cubbi project remove github.com/hello/private ``` ### Project Configuration -Projects are stored in the MC service and referenced by their repository URL. The configuration includes: +Projects are stored in the Cubbi service and referenced by their repository URL. The configuration includes: ```yaml # Project configuration @@ -457,50 +457,50 @@ Each image is a Docker container with a standardized structure: ``` / ├── entrypoint.sh # Container initialization -├── mc-init.sh # Standardized initialization script -├── mc-image.yaml # Image metadata and configuration +├── cubbi-init.sh # Standardized initialization script +├── cubbi-image.yaml # Image metadata and configuration ├── tool/ # AI tool installation └── ssh/ # SSH server configuration ``` ### Standardized Initialization Script -All images include a standardized `mc-init.sh` script that handles common initialization tasks: +All images include a standardized `cubbi-init.sh` script that handles common initialization tasks: ```bash #!/bin/bash # Project initialization -if [ -n "$MC_PROJECT_URL" ]; then - echo "Initializing project: $MC_PROJECT_URL" +if [ -n "$CUBBI_PROJECT_URL" ]; then + echo "Initializing project: $CUBBI_PROJECT_URL" # Set up SSH key if provided - if [ -n "$MC_GIT_SSH_KEY" ]; then + if [ -n "$CUBBI_GIT_SSH_KEY" ]; then mkdir -p ~/.ssh - echo "$MC_GIT_SSH_KEY" > ~/.ssh/id_ed25519 + echo "$CUBBI_GIT_SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null fi # Set up token if provided - if [ -n "$MC_GIT_TOKEN" ]; then + if [ -n "$CUBBI_GIT_TOKEN" ]; then git config --global credential.helper store - echo "https://$MC_GIT_TOKEN:x-oauth-basic@github.com" > ~/.git-credentials + echo "https://$CUBBI_GIT_TOKEN:x-oauth-basic@github.com" > ~/.git-credentials fi # Clone repository - git clone $MC_PROJECT_URL /app + git clone $CUBBI_PROJECT_URL /app cd /app # Run project-specific initialization if present - if [ -f "/app/.mc/init.sh" ]; then - bash /app/.mc/init.sh + if [ -f "/app/.cubbi/init.sh" ]; then + bash /app/.cubbi/init.sh fi fi # Image-specific initialization continues... ``` -### Image Configuration (mc-image.yaml) +### Image Configuration (cubbi-image.yaml) ```yaml name: goose @@ -509,7 +509,7 @@ version: 1.0.0 maintainer: team@monadical.com init: - pre_command: /mc-init.sh + pre_command: /cubbi-init.sh command: /entrypoint.sh environment: @@ -523,21 +523,21 @@ environment: required: false # Project environment variables - - name: MC_PROJECT_URL + - name: CUBBI_PROJECT_URL description: Project repository URL required: false - - name: MC_PROJECT_TYPE + - name: CUBBI_PROJECT_TYPE description: Project repository type (git, svn, etc.) required: false default: git - - name: MC_GIT_SSH_KEY + - name: CUBBI_GIT_SSH_KEY description: SSH key for Git authentication required: false sensitive: true - - name: MC_GIT_TOKEN + - name: CUBBI_GIT_TOKEN description: Token for Git authentication required: false sensitive: true @@ -552,7 +552,7 @@ volumes: persistent_configs: - source: "/app/.goose" - target: "/mc-config/goose" + target: "/cubbi-config/goose" type: "directory" description: "Goose memory and configuration" ``` @@ -568,32 +568,32 @@ persistent_configs: ### Docker Network Integration -MC provides flexible network management for containers: +Cubbi provides flexible network management for containers: -1. **Default MC Network**: - - Each container is automatically connected to the MC network (`mc-network` by default) +1. **Default Cubbi Network**: + - Each container is automatically connected to the Cubbi network (`cubbi-network` by default) - This ensures containers can communicate with each other 2. **External Network Connection**: - Containers can be connected to one or more external Docker networks - This allows integration with existing infrastructure (e.g., databases, web servers) - - Networks can be specified at session creation time: `mc session create --network mynetwork` + - Networks can be specified at session creation time: `cubbi session create --network mynetwork` 3. **Default Networks Configuration**: - Users can configure default networks in their configuration - These networks will be used for all new sessions unless overridden - - Managed with `mc config network` commands + - Managed with `cubbi config network` commands 4. **Network Command Examples**: ```bash # Use with session creation - mc session create --network teamnet + cubbi session create --network teamnet # Use with multiple networks - mc session create --network teamnet --network dbnet + cubbi session create --network teamnet --network dbnet # Configure default networks - mc config network add teamnet + cubbi config network add teamnet ``` ## Security Considerations @@ -606,15 +606,15 @@ MC provides flexible network management for containers: ## Deployment -### MC Service Deployment +### Cubbi Service Deployment ```yaml -# docker-compose.yml for MC Service +# docker-compose.yml for Cubbi Service version: '3.8' services: - mc-service: - image: monadical/mc-service:latest + cubbi-service: + image: monadical/cubbi-service:latest volumes: - /var/run/docker.sock:/var/run/docker.sock - ./config:/app/config @@ -624,10 +624,10 @@ services: - AUTH_URL=https://authentik.monadical.io - LANGFUSE_API_KEY=your_api_key networks: - - mc-network + - cubbi-network networks: - mc-network: + cubbi-network: driver: bridge ``` @@ -637,33 +637,33 @@ networks: 1. User adds project repository with authentication: ```bash - mc project add github.com/hello/private --ssh-key ~/.ssh/id_ed25519 + cubbi project add github.com/hello/private --ssh-key ~/.ssh/id_ed25519 ``` -2. MC CLI reads the SSH key, encrypts it, and sends to MC Service +2. Cubbi CLI reads the SSH key, encrypts it, and sends to Cubbi Service -3. MC Service stores the project configuration securely +3. Cubbi Service stores the project configuration securely ### Using a Project in a Session 1. User creates a session with a project: ```bash - mc -r monadical git@github.com:hello/private + cubbi -r monadical git@github.com:hello/private ``` -2. MC Service: +2. Cubbi Service: - Identifies the project from the URL - Retrieves project authentication details - Sets up environment variables: ``` - MC_PROJECT_URL=git@github.com:hello/private - MC_PROJECT_TYPE=git - MC_GIT_SSH_KEY= + CUBBI_PROJECT_URL=git@github.com:hello/private + CUBBI_PROJECT_TYPE=git + CUBBI_GIT_SSH_KEY= ``` - Creates container with these environment variables 3. Container initialization: - - The standardized `mc-init.sh` script detects the project environment variables + - The standardized `cubbi-init.sh` script detects the project environment variables - Sets up SSH key or token authentication - Clones the repository to `/app` - Runs any project-specific initialization scripts @@ -673,7 +673,7 @@ networks: ## Implementation Roadmap 1. **Phase 1**: Local CLI tool with Docker integration -2. **Phase 2**: MC Service REST API with basic container management +2. **Phase 2**: Cubbi Service REST API with basic container management 3. **Phase 3**: Authentication and secure connections 4. **Phase 4**: Project management functionality 5. **Phase 5**: Image implementation (Goose, Aider, Claude Code) diff --git a/docs/specs/2_MCP_SERVER.md b/docs/specs/2_MCP_SERVER.md index 070200f..6d46da9 100644 --- a/docs/specs/2_MCP_SERVER.md +++ b/docs/specs/2_MCP_SERVER.md @@ -2,7 +2,7 @@ ## Overview -This document specifies the implementation for Model Control Protocol (MCP) server support in the Monadical Container (MC) system. The MCP server feature allows users to connect, build, and manage external MCP servers that can be attached to MC sessions. +This document specifies the implementation for Model Control Protocol (MCP) server support in the Cubbi system. The MCP server feature allows users to connect, build, and manage external MCP servers that can be attached to Cubbi sessions. An MCP server is a service that can be accessed by a image (such as Goose or Claude Code) to extend the LLM's capabilities through tool calls. It can be either: - A local stdio-based MCP server running in a container (accessed via an SSE proxy) @@ -53,48 +53,48 @@ mcps: ### MCP Management ``` -mc mcp list # List all configured MCP servers and their status -mc mcp status # Show detailed status of a specific MCP server -mc mcp start # Start an MCP server container -mc mcp stop # Stop and remove an MCP server container -mc mcp restart # Restart an MCP server container -mc mcp start --all # Start all MCP server containers -mc mcp stop --all # Stop and remove all MCP server containers -mc mcp inspector # Run the MCP Inspector UI with network connectivity to all MCP servers -mc mcp inspector --client-port --server-port # Run with custom client port (default: 5173) and server port (default: 3000) -mc mcp inspector --detach # Run the inspector in detached mode -mc mcp inspector --stop # Stop the running inspector -mc mcp logs # Show logs for an MCP server container +cubbi mcp list # List all configured MCP servers and their status +cubbi mcp status # Show detailed status of a specific MCP server +cubbi mcp start # Start an MCP server container +cubbi mcp stop # Stop and remove an MCP server container +cubbi mcp restart # Restart an MCP server container +cubbi mcp start --all # Start all MCP server containers +cubbi mcp stop --all # Stop and remove all MCP server containers +cubbi mcp inspector # Run the MCP Inspector UI with network connectivity to all MCP servers +cubbi mcp inspector --client-port --server-port # Run with custom client port (default: 5173) and server port (default: 3000) +cubbi mcp inspector --detach # Run the inspector in detached mode +cubbi mcp inspector --stop # Stop the running inspector +cubbi mcp logs # Show logs for an MCP server container ``` ### MCP Configuration ``` # Add a proxy-based MCP server (default) -mc mcp add [--command CMD] [--proxy-image IMG] [--sse-port PORT] [--sse-host HOST] [--allow-origin ORIGIN] [--env KEY=VALUE...] +cubbi mcp add [--command CMD] [--proxy-image IMG] [--sse-port PORT] [--sse-host HOST] [--allow-origin ORIGIN] [--env KEY=VALUE...] # Add a remote MCP server -mc mcp add-remote [--header KEY=VALUE...] +cubbi mcp add-remote [--header KEY=VALUE...] # Remove an MCP configuration -mc mcp remove +cubbi mcp remove ``` ### Session Integration ``` -mc session create [--mcp ] # Create a session with an MCP server attached +cubbi session create [--mcp ] # Create a session with an MCP server attached ``` ## Implementation Details ### MCP Container Management -1. MCP containers will have their own dedicated Docker network (`mc-mcp-network`) +1. MCP containers will have their own dedicated Docker network (`cubbi-mcp-network`) 2. Session containers will be attached to both their session network and the MCP network when using an MCP 3. MCP containers will be persistent across sessions unless explicitly stopped -4. MCP containers will be named with a prefix to identify them (`mc_mcp_`) -5. Each MCP container will have a network alias matching its name without the prefix (e.g., `mc_mcp_github` will have the alias `github`) +4. MCP containers will be named with a prefix to identify them (`cubbi_mcp_`) +5. Each MCP container will have a network alias matching its name without the prefix (e.g., `cubbi_mcp_github` will have the alias `github`) 6. Network aliases enable DNS-based service discovery between containers ### MCP Inspector diff --git a/pyproject.toml b/pyproject.toml index 567a273..6f24d99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] -name = "mcontainer" +name = "cubbi" version = "0.1.0" -description = "Monadical Container Tool" +description = "Cubbi Container Tool" readme = "README.md" requires-python = ">=3.12" dependencies = [ @@ -24,8 +24,8 @@ dev = [ ] [project.scripts] -mc = "mcontainer.cli:app" -mcx = "mcontainer.cli:session_create_entry_point" +cubbi = "cubbi.cli:app" +cubbix = "cubbi.cli:session_create_entry_point" [tool.ruff] line-length = 88 diff --git a/tests/conftest.py b/tests/conftest.py index 5e85ea1..df99af6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ """ -Common test fixtures for Monadical Container tests. +Common test fixtures for Cubbi Container tests. """ import uuid @@ -9,11 +9,11 @@ import docker from pathlib import Path from unittest.mock import patch -from mcontainer.container import ContainerManager -from mcontainer.session import SessionManager -from mcontainer.config import ConfigManager -from mcontainer.models import Session, SessionStatus -from mcontainer.user_config import UserConfigManager +from cubbi.container import ContainerManager +from cubbi.session import SessionManager +from cubbi.config import ConfigManager +from cubbi.models import Session, SessionStatus +from cubbi.user_config import UserConfigManager # Check if Docker is available @@ -81,7 +81,7 @@ def isolated_config_manager(): @pytest.fixture def mock_session_manager(): """Mock the SessionManager class.""" - with patch("mcontainer.cli.session_manager") as mock_manager: + with patch("cubbi.cli.session_manager") as mock_manager: yield mock_manager @@ -96,7 +96,7 @@ def mock_container_manager(): ports={"8080": "8080"}, ) - with patch("mcontainer.cli.container_manager") as mock_manager: + with patch("cubbi.cli.container_manager") as mock_manager: # Set behaviors to avoid TypeErrors mock_manager.list_sessions.return_value = [] mock_manager.create_session.return_value = mock_session @@ -149,7 +149,7 @@ def test_file_content(temp_dir): @pytest.fixture def test_network_name(): """Generate a unique network name for testing.""" - return f"mc-test-network-{uuid.uuid4().hex[:8]}" + return f"cubbi-test-network-{uuid.uuid4().hex[:8]}" @pytest.fixture @@ -175,5 +175,5 @@ def docker_test_network(test_network_name): @pytest.fixture def patched_config_manager(isolated_config): """Patch the UserConfigManager in cli.py to use our isolated instance.""" - with patch("mcontainer.cli.user_config", isolated_config): + with patch("cubbi.cli.user_config", isolated_config): yield isolated_config diff --git a/tests/test_cli.py b/tests/test_cli.py index 78dc276..94f0623 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,6 @@ from typer.testing import CliRunner -from mcontainer.cli import app +from cubbi.cli import app runner = CliRunner() @@ -9,7 +9,7 @@ def test_version() -> None: """Test version command""" result = runner.invoke(app, ["version"]) assert result.exit_code == 0 - assert "MC - Monadical Container Tool" in result.stdout + assert "Cubbi - Cubbi Container Tool" in result.stdout def test_session_list() -> None: @@ -25,4 +25,4 @@ def test_help() -> None: result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "Usage" in result.stdout - assert "Monadical Container Tool" in result.stdout + assert "Cubbi Container Tool" in result.stdout diff --git a/tests/test_config_commands.py b/tests/test_config_commands.py index 0660c8b..419522f 100644 --- a/tests/test_config_commands.py +++ b/tests/test_config_commands.py @@ -2,11 +2,11 @@ Tests for the configuration management commands. """ -from mcontainer.cli import app +from cubbi.cli import app def test_config_list(cli_runner, patched_config_manager): - """Test the 'mc config list' command.""" + """Test the 'cubbi config list' command.""" result = cli_runner.invoke(app, ["config", "list"]) assert result.exit_code == 0 @@ -20,7 +20,7 @@ def test_config_list(cli_runner, patched_config_manager): def test_config_get(cli_runner, patched_config_manager): - """Test the 'mc config get' command.""" + """Test the 'cubbi config get' command.""" # Test getting an existing value result = cli_runner.invoke(app, ["config", "get", "defaults.image"]) @@ -36,7 +36,7 @@ def test_config_get(cli_runner, patched_config_manager): def test_config_set(cli_runner, patched_config_manager): - """Test the 'mc config set' command.""" + """Test the 'cubbi config set' command.""" # Test setting a string value result = cli_runner.invoke(app, ["config", "set", "defaults.image", "claude"]) @@ -60,7 +60,7 @@ def test_config_set(cli_runner, patched_config_manager): def test_volume_list_empty(cli_runner, patched_config_manager): - """Test the 'mc config volume list' command with no volumes.""" + """Test the 'cubbi config volume list' command with no volumes.""" result = cli_runner.invoke(app, ["config", "volume", "list"]) assert result.exit_code == 0 @@ -133,7 +133,7 @@ def test_volume_add_nonexistent_path(cli_runner, patched_config_manager, monkeyp def test_network_list_empty(cli_runner, patched_config_manager): - """Test the 'mc config network list' command with no networks.""" + """Test the 'cubbi config network list' command with no networks.""" result = cli_runner.invoke(app, ["config", "network", "list"]) assert result.exit_code == 0 diff --git a/tests/test_integration_docker.py b/tests/test_integration_docker.py index 4535e9c..5467722 100644 --- a/tests/test_integration_docker.py +++ b/tests/test_integration_docker.py @@ -1,5 +1,5 @@ """ -Integration tests for Docker interactions in Monadical Container. +Integration tests for Docker interactions in Cubbi Container. These tests require Docker to be running. """ @@ -31,7 +31,7 @@ def test_integration_session_create_with_volumes(container_manager, test_file_co # Create a session with a volume mount session = container_manager.create_session( image_name="goose", - session_name=f"mc-test-volume-{uuid.uuid4().hex[:8]}", + session_name=f"cubbi-test-volume-{uuid.uuid4().hex[:8]}", mount_local=False, # Don't mount current directory volumes={str(test_file): {"bind": "/test/volume_test.txt", "mode": "ro"}}, ) @@ -66,7 +66,7 @@ def test_integration_session_create_with_networks( # Create a session with the test network session = container_manager.create_session( image_name="goose", - session_name=f"mc-test-network-{uuid.uuid4().hex[:8]}", + session_name=f"cubbi-test-network-{uuid.uuid4().hex[:8]}", mount_local=False, # Don't mount current directory networks=[docker_test_network], ) @@ -85,7 +85,7 @@ def test_integration_session_create_with_networks( container = client.containers.get(session.container_id) container_networks = container.attrs["NetworkSettings"]["Networks"] - # Container should be connected to both the default mc-network and our test network + # Container should be connected to both the default cubbi-network and our test network assert docker_test_network in container_networks # Verify network interface exists in container @@ -93,7 +93,7 @@ def test_integration_session_create_with_networks( session.container_id, "ip link show | grep -v 'lo' | wc -l" ) - # Should have at least 2 interfaces (eth0 for mc-network, eth1 for test network) + # Should have at least 2 interfaces (eth0 for cubbi-network, eth1 for test network) assert int(network_interfaces) >= 2 finally: diff --git a/tests/test_mcp_commands.py b/tests/test_mcp_commands.py index ba106d9..7821a86 100644 --- a/tests/test_mcp_commands.py +++ b/tests/test_mcp_commands.py @@ -4,15 +4,15 @@ Tests for the MCP server management commands. import pytest from unittest.mock import patch -from mcontainer.cli import app +from cubbi.cli import app def test_mcp_list_empty(cli_runner, patched_config_manager): - """Test the 'mc mcp list' command with no MCPs configured.""" + """Test the 'cubbi mcp list' command with no MCPs configured.""" # Make sure mcps is empty patched_config_manager.set("mcps", []) - with patch("mcontainer.cli.mcp_manager.list_mcps") as mock_list_mcps: + with patch("cubbi.cli.mcp_manager.list_mcps") as mock_list_mcps: mock_list_mcps.return_value = [] result = cli_runner.invoke(app, ["mcp", "list"]) @@ -94,7 +94,7 @@ def test_mcp_remove(cli_runner, patched_config_manager): ) # Mock the get_mcp and remove_mcp methods - with patch("mcontainer.cli.mcp_manager.get_mcp") as mock_get_mcp: + with patch("cubbi.cli.mcp_manager.get_mcp") as mock_get_mcp: # First make get_mcp return our MCP mock_get_mcp.return_value = { "name": "test-mcp", @@ -128,7 +128,7 @@ def test_mcp_status(cli_runner, patched_config_manager, mock_container_manager): ) # First mock get_mcp to return our MCP config - with patch("mcontainer.cli.mcp_manager.get_mcp") as mock_get_mcp: + with patch("cubbi.cli.mcp_manager.get_mcp") as mock_get_mcp: mock_get_mcp.return_value = { "name": "test-docker-mcp", "type": "docker", @@ -138,7 +138,7 @@ def test_mcp_status(cli_runner, patched_config_manager, mock_container_manager): } # Then mock the get_mcp_status method - with patch("mcontainer.cli.mcp_manager.get_mcp_status") as mock_get_status: + with patch("cubbi.cli.mcp_manager.get_mcp_status") as mock_get_status: mock_get_status.return_value = { "status": "running", "container_id": "test-container-id", @@ -262,7 +262,7 @@ def test_mcp_logs(cli_runner, patched_config_manager, mock_container_manager): ) # Mock the logs operation - with patch("mcontainer.cli.mcp_manager.get_mcp_logs") as mock_get_logs: + with patch("cubbi.cli.mcp_manager.get_mcp_logs") as mock_get_logs: mock_get_logs.return_value = "Test log output" # View MCP logs @@ -288,7 +288,7 @@ def test_session_with_mcp(cli_runner, patched_config_manager, mock_container_man ) # Mock the session creation with MCP - from mcontainer.models import Session, SessionStatus + from cubbi.models import Session, SessionStatus # timestamp no longer needed since we don't use created_at in Session mock_container_manager.create_session.return_value = Session( diff --git a/tests/test_mcp_port_binding.py b/tests/test_mcp_port_binding.py index 6b8b7e7..556a629 100644 --- a/tests/test_mcp_port_binding.py +++ b/tests/test_mcp_port_binding.py @@ -6,7 +6,7 @@ import time import uuid from conftest import requires_docker -from mcontainer.mcp import MCPManager +from cubbi.mcp import MCPManager @requires_docker diff --git a/tests/test_session_commands.py b/tests/test_session_commands.py index 15f52bc..06bb2b6 100644 --- a/tests/test_session_commands.py +++ b/tests/test_session_commands.py @@ -5,11 +5,11 @@ Tests for the session management commands. from unittest.mock import patch -from mcontainer.cli import app +from cubbi.cli import app def test_session_list_empty(cli_runner, mock_container_manager): - """Test 'mc session list' with no active sessions.""" + """Test 'cubbi session list' with no active sessions.""" mock_container_manager.list_sessions.return_value = [] result = cli_runner.invoke(app, ["session", "list"]) @@ -19,9 +19,9 @@ def test_session_list_empty(cli_runner, mock_container_manager): def test_session_list_with_sessions(cli_runner, mock_container_manager): - """Test 'mc session list' with active sessions.""" + """Test 'cubbi session list' with active sessions.""" # Create a mock session and set list_sessions to return it - from mcontainer.models import Session, SessionStatus + from cubbi.models import Session, SessionStatus mock_session = Session( id="test-session-id", @@ -40,9 +40,9 @@ def test_session_list_with_sessions(cli_runner, mock_container_manager): def test_session_create_basic(cli_runner, mock_container_manager): - """Test 'mc session create' with basic options.""" + """Test 'cubbi session create' with basic options.""" # We need to patch user_config.get with a side_effect to handle different keys - with patch("mcontainer.cli.user_config") as mock_user_config: + with patch("cubbi.cli.user_config") as mock_user_config: # Handle different key requests appropriately def mock_get_side_effect(key, default=None): if key == "defaults.image": @@ -76,7 +76,7 @@ def test_session_create_basic(cli_runner, mock_container_manager): def test_session_close(cli_runner, mock_container_manager): - """Test 'mc session close' command.""" + """Test 'cubbi session close' command.""" mock_container_manager.close_session.return_value = True result = cli_runner.invoke(app, ["session", "close", "test-session-id"]) @@ -87,9 +87,9 @@ def test_session_close(cli_runner, mock_container_manager): def test_session_close_all(cli_runner, mock_container_manager): - """Test 'mc session close --all' command.""" + """Test 'cubbi session close --all' command.""" # Set up mock sessions - from mcontainer.models import Session, SessionStatus + from cubbi.models import Session, SessionStatus # timestamp no longer needed since we don't use created_at in Session mock_sessions = [ diff --git a/uv.lock b/uv.lock index a6c4428..c56ea30 100644 --- a/uv.lock +++ b/uv.lock @@ -75,6 +75,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "cubbi" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "docker" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "rich" }, + { name = "typer" }, +] + +[package.optional-dependencies] +dev = [ + { name = "mypy" }, + { name = "pytest" }, + { name = "ruff" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "docker", specifier = ">=7.0.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.7.0" }, + { name = "pydantic", specifier = ">=2.5.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4.0" }, + { name = "pyyaml", specifier = ">=6.0.1" }, + { name = "rich", specifier = ">=13.6.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.9" }, + { name = "typer", specifier = ">=0.9.0" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.3.5" }] + [[package]] name = "docker" version = "7.1.0" @@ -119,45 +158,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] -[[package]] -name = "mcontainer" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "docker" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "rich" }, - { name = "typer" }, -] - -[package.optional-dependencies] -dev = [ - { name = "mypy" }, - { name = "pytest" }, - { name = "ruff" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, -] - -[package.metadata] -requires-dist = [ - { name = "docker", specifier = ">=7.0.0" }, - { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.7.0" }, - { name = "pydantic", specifier = ">=2.5.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4.0" }, - { name = "pyyaml", specifier = ">=6.0.1" }, - { name = "rich", specifier = ">=13.6.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.9" }, - { name = "typer", specifier = ">=0.9.0" }, -] - -[package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=8.3.5" }] - [[package]] name = "mdurl" version = "0.1.2"