| import subprocess |
| import os |
| from typing import Tuple |
|
|
| class TerminalSandbox: |
| def __init__(self, config): |
| self.config = config |
| self.external_drive = config.get("external_drive_path", "/mnt/shorekeeper_drive") |
| self.allowed_commands = config.get("allowed_commands", ["python3", "pip", "git", "ls", "cat", "mkdir", "touch", "echo"]) |
| |
| |
| os.makedirs(self.external_drive, exist_ok=True) |
| print(f"Sandbox initialized. Projects will be stored in: {self.external_drive}") |
| |
| def start(self): |
| """No Docker mode - use local environment""" |
| return True |
| |
| def execute(self, command: str, timeout: int = 30) -> Tuple[str, int]: |
| """Execute command locally""" |
| cmd_parts = command.strip().split() |
| if cmd_parts and cmd_parts[0] not in self.allowed_commands: |
| return f"Command '{cmd_parts[0]}' not allowed. Allowed: {self.allowed_commands}", 1 |
| |
| try: |
| result = subprocess.run( |
| command, |
| shell=True, |
| capture_output=True, |
| text=True, |
| timeout=timeout, |
| cwd=self.external_drive |
| ) |
| return result.stdout + result.stderr, result.returncode |
| except subprocess.TimeoutExpired: |
| return f"Command timed out after {timeout} seconds", -1 |
| except Exception as e: |
| return str(e), -1 |
| |
| def create_project(self, project_name: str) -> str: |
| """Create a new project folder on the external drive""" |
| project_path = os.path.join(self.external_drive, project_name) |
| os.makedirs(project_path, exist_ok=True) |
| |
| readme_path = os.path.join(project_path, "README.md") |
| with open(readme_path, "w") as f: |
| f.write(f"# Project: {project_name}\n") |
| f.write(f"# Created by SHOREKEEPER\n") |
| |
| return project_path |
| |
| def list_projects(self) -> list: |
| """List all projects on the external drive""" |
| try: |
| projects = [d for d in os.listdir(self.external_drive) |
| if os.path.isdir(os.path.join(self.external_drive, d))] |
| return projects |
| except Exception: |
| return [] |
| |
| def stop(self): |
| """Clean shutdown""" |
| pass |
|
|