Spaces:
Build error
Build error
import asyncio | |
import os | |
import shutil | |
import sys | |
import uuid | |
from dataclasses import dataclass | |
from pathlib import Path | |
from typing import Optional | |
from openhands.core.logger import openhands_logger as logger | |
from openhands.events.action import Action | |
from openhands.events.observation import Observation | |
from openhands.runtime.plugins.requirement import Plugin, PluginRequirement | |
from openhands.runtime.utils.system import check_port_available | |
from openhands.utils.shutdown_listener import should_continue | |
class VSCodeRequirement(PluginRequirement): | |
name: str = 'vscode' | |
class VSCodePlugin(Plugin): | |
name: str = 'vscode' | |
vscode_port: Optional[int] = None | |
vscode_connection_token: Optional[str] = None | |
gateway_process: asyncio.subprocess.Process | |
async def initialize(self, username: str) -> None: | |
# Check if we're on Windows - VSCode plugin is not supported on Windows | |
if os.name == 'nt' or sys.platform == 'win32': | |
self.vscode_port = None | |
self.vscode_connection_token = None | |
logger.warning( | |
'VSCode plugin is not supported on Windows. Plugin will be disabled.' | |
) | |
return | |
if username not in ['root', 'openhands']: | |
self.vscode_port = None | |
self.vscode_connection_token = None | |
logger.warning( | |
'VSCodePlugin is only supported for root or openhands user. ' | |
'It is not yet supported for other users (i.e., when running LocalRuntime).' | |
) | |
return | |
# Set up VSCode settings.json | |
self._setup_vscode_settings() | |
try: | |
self.vscode_port = int(os.environ['VSCODE_PORT']) | |
except (KeyError, ValueError): | |
logger.warning( | |
'VSCODE_PORT environment variable not set or invalid. VSCode plugin will be disabled.' | |
) | |
return | |
self.vscode_connection_token = str(uuid.uuid4()) | |
if not check_port_available(self.vscode_port): | |
logger.warning( | |
f'Port {self.vscode_port} is not available. VSCode plugin will be disabled.' | |
) | |
return | |
cmd = ( | |
f"su - {username} -s /bin/bash << 'EOF'\n" | |
f'sudo chown -R {username}:{username} /openhands/.openvscode-server\n' | |
'cd /workspace\n' | |
f'exec /openhands/.openvscode-server/bin/openvscode-server --host 0.0.0.0 --connection-token {self.vscode_connection_token} --port {self.vscode_port} --disable-workspace-trust\n' | |
'EOF' | |
) | |
# Using asyncio.create_subprocess_shell instead of subprocess.Popen | |
# to avoid ASYNC101 linting error | |
self.gateway_process = await asyncio.create_subprocess_shell( | |
cmd, | |
stderr=asyncio.subprocess.STDOUT, | |
stdout=asyncio.subprocess.PIPE, | |
) | |
# read stdout until the kernel gateway is ready | |
output = '' | |
while should_continue() and self.gateway_process.stdout is not None: | |
line_bytes = await self.gateway_process.stdout.readline() | |
line = line_bytes.decode('utf-8') | |
print(line) | |
output += line | |
if 'at' in line: | |
break | |
await asyncio.sleep(1) | |
logger.debug('Waiting for VSCode server to start...') | |
logger.debug( | |
f'VSCode server started at port {self.vscode_port}. Output: {output}' | |
) | |
def _setup_vscode_settings(self) -> None: | |
""" | |
Set up VSCode settings by creating the .vscode directory in the workspace | |
and copying the settings.json file there. | |
""" | |
# Get the path to the settings.json file in the plugin directory | |
current_dir = Path(__file__).parent | |
settings_path = current_dir / 'settings.json' | |
# Create the .vscode directory in the workspace if it doesn't exist | |
vscode_dir = Path('/workspace/.vscode') | |
vscode_dir.mkdir(parents=True, exist_ok=True) | |
# Copy the settings.json file to the .vscode directory | |
target_path = vscode_dir / 'settings.json' | |
shutil.copy(settings_path, target_path) | |
# Make sure the settings file is readable and writable by all users | |
os.chmod(target_path, 0o666) | |
logger.debug(f'VSCode settings copied to {target_path}') | |
async def run(self, action: Action) -> Observation: | |
"""Run the plugin for a given action.""" | |
raise NotImplementedError('VSCodePlugin does not support run method') | |