mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
4 Commits
fix-github
...
simple-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7066f52593 | ||
|
|
f0c537f32f | ||
|
|
454776e040 | ||
|
|
bf5f68d080 |
@@ -1,5 +1,7 @@
|
||||
import asyncio
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -33,6 +35,7 @@ from openhands.cli.utils import (
|
||||
read_file,
|
||||
write_to_file,
|
||||
)
|
||||
from openhands.cli.vscode_extension import get_vsix_path
|
||||
from openhands.core.config import (
|
||||
OpenHandsConfig,
|
||||
)
|
||||
@@ -159,6 +162,8 @@ async def handle_commands(
|
||||
await handle_settings_command(config, settings_store)
|
||||
elif command == '/resume':
|
||||
close_repl, new_session_requested = await handle_resume_command(event_stream)
|
||||
elif command == '/vscode-extension':
|
||||
handle_vscode_extension_command()
|
||||
elif command == '/mcp':
|
||||
await handle_mcp_command(config)
|
||||
else:
|
||||
@@ -411,6 +416,60 @@ def check_folder_security_agreement(config: OpenHandsConfig, current_dir: str) -
|
||||
return True
|
||||
|
||||
|
||||
def handle_vscode_extension_command() -> None:
|
||||
"""
|
||||
Handle the /vscode-extension command.
|
||||
|
||||
This command helps users install the OpenHands VSCode extension manually
|
||||
by providing the path to the VSIX file.
|
||||
"""
|
||||
print_formatted_text('\nOpenHands VSCode Extension Installation\n')
|
||||
|
||||
vsix_path = get_vsix_path()
|
||||
if not vsix_path:
|
||||
print_formatted_text(
|
||||
'❌ Could not find or download the VSCode extension VSIX file.'
|
||||
)
|
||||
print_formatted_text('Please check your internet connection and try again.')
|
||||
return
|
||||
|
||||
# Extract version information from the filename if possible
|
||||
version_info = ''
|
||||
if vsix_path.name.startswith('openhands-vscode-'):
|
||||
version_match = re.search(r'openhands-vscode-([0-9.]+)\.vsix', vsix_path.name)
|
||||
if version_match:
|
||||
version_info = f' (version {version_match.group(1)})'
|
||||
|
||||
# Create a user-friendly location for the VSIX file
|
||||
home_dir = Path.home()
|
||||
downloads_dir = home_dir / 'Downloads'
|
||||
if not downloads_dir.exists():
|
||||
downloads_dir = home_dir
|
||||
|
||||
target_path = downloads_dir / vsix_path.name
|
||||
|
||||
try:
|
||||
shutil.copy(vsix_path, target_path)
|
||||
print_formatted_text(
|
||||
f'✅ VSCode extension{version_info} VSIX file saved to: {target_path}'
|
||||
)
|
||||
print_formatted_text('\nTo install the extension:')
|
||||
print_formatted_text('1. Open VSCode')
|
||||
print_formatted_text('2. Go to Extensions view (Ctrl+Shift+X)')
|
||||
print_formatted_text(
|
||||
'3. Click on the "..." menu at the top of the Extensions view'
|
||||
)
|
||||
print_formatted_text('4. Select "Install from VSIX..."')
|
||||
print_formatted_text(f'5. Navigate to and select: {target_path}')
|
||||
print_formatted_text(
|
||||
'\nAlternatively, you can run this command in your terminal:'
|
||||
)
|
||||
print_formatted_text(f'code --install-extension {target_path}')
|
||||
except Exception as e:
|
||||
print_formatted_text(f'❌ Error saving VSIX file: {e}')
|
||||
print_formatted_text(f'The VSIX file is available at: {vsix_path}')
|
||||
|
||||
|
||||
async def handle_mcp_command(config: OpenHandsConfig) -> None:
|
||||
"""Handle MCP command with interactive menu."""
|
||||
action = cli_confirm(
|
||||
|
||||
@@ -81,6 +81,7 @@ COMMANDS = {
|
||||
'/new': 'Create a new conversation',
|
||||
'/settings': 'Display and modify current settings',
|
||||
'/resume': 'Resume the agent when paused',
|
||||
'/vscode-extension': 'Get the VSCode extension VSIX file for manual installation',
|
||||
'/mcp': 'Manage MCP server configuration and view errors',
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@ import importlib.resources
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from urllib.error import URLError
|
||||
|
||||
from openhands.core.logger import openhands_logger as logger
|
||||
@@ -124,7 +127,7 @@ def attempt_vscode_extension_install():
|
||||
|
||||
# If all attempts failed, inform the user (but don't create flag - allow retry).
|
||||
print(
|
||||
'INFO: Automatic installation failed. Please check the OpenHands documentation for manual installation instructions.'
|
||||
'INFO: Automatic installation failed. You can use the /vscode-extension command to get the extension VSIX file for manual installation.'
|
||||
)
|
||||
print(
|
||||
f'INFO: Will retry installation next time you run OpenHands in {editor_name}.'
|
||||
@@ -240,35 +243,39 @@ def _attempt_bundled_install(editor_command: str, editor_name: str) -> bool:
|
||||
bool: True if installation succeeded, False otherwise
|
||||
"""
|
||||
try:
|
||||
vsix_filename = 'openhands-vscode-0.0.1.vsix'
|
||||
with importlib.resources.as_file(
|
||||
importlib.resources.files('openhands').joinpath(
|
||||
'integrations', 'vscode', vsix_filename
|
||||
)
|
||||
) as vsix_path:
|
||||
if vsix_path.exists():
|
||||
process = subprocess.run(
|
||||
[
|
||||
editor_command,
|
||||
'--install-extension',
|
||||
str(vsix_path),
|
||||
'--force',
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if process.returncode == 0:
|
||||
print(
|
||||
f'INFO: Bundled {editor_name} extension installed successfully.'
|
||||
vscode_dir = importlib.resources.files('openhands').joinpath(
|
||||
'integrations', 'vscode'
|
||||
)
|
||||
with importlib.resources.as_file(vscode_dir) as vscode_path:
|
||||
if vscode_path.exists() and vscode_path.is_dir():
|
||||
# Find any .vsix file in the directory
|
||||
vsix_files = list(vscode_path.glob('*.vsix'))
|
||||
if vsix_files:
|
||||
vsix_path = vsix_files[0] # Use the first .vsix file found
|
||||
process = subprocess.run(
|
||||
[
|
||||
editor_command,
|
||||
'--install-extension',
|
||||
str(vsix_path),
|
||||
'--force',
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
return True
|
||||
if process.returncode == 0:
|
||||
print(
|
||||
f'INFO: Bundled {editor_name} extension installed successfully.'
|
||||
)
|
||||
return True
|
||||
else:
|
||||
logger.debug(
|
||||
f'Bundled .vsix installation failed: {process.stderr.strip()}'
|
||||
)
|
||||
else:
|
||||
logger.debug(
|
||||
f'Bundled .vsix installation failed: {process.stderr.strip()}'
|
||||
)
|
||||
logger.debug(f'No .vsix files found in {vscode_path}.')
|
||||
else:
|
||||
logger.debug(f'Bundled .vsix not found at {vsix_path}.')
|
||||
logger.debug(f'Bundled vscode directory not found at {vscode_path}.')
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f'Could not auto-install extension. Please make sure "code" command is in PATH. Error: {e}'
|
||||
@@ -277,6 +284,41 @@ def _attempt_bundled_install(editor_command: str, editor_name: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def get_vsix_path() -> Optional[Path]:
|
||||
"""
|
||||
Get the path to the bundled VSIX file or download it from GitHub if not available.
|
||||
|
||||
Returns:
|
||||
Path to the VSIX file, or None if not found
|
||||
"""
|
||||
# First try to get the bundled VSIX by looking for any .vsix file in the integrations/vscode directory
|
||||
try:
|
||||
vscode_dir = importlib.resources.files('openhands').joinpath(
|
||||
'integrations', 'vscode'
|
||||
)
|
||||
with importlib.resources.as_file(vscode_dir) as vscode_path:
|
||||
if vscode_path.exists() and vscode_path.is_dir():
|
||||
# Find any .vsix file in the directory
|
||||
vsix_files = list(vscode_path.glob('*.vsix'))
|
||||
if vsix_files:
|
||||
vsix_path = vsix_files[0] # Use the first .vsix file found
|
||||
# Create a copy in a temporary location that will persist
|
||||
temp_dir = Path(tempfile.gettempdir()) / 'openhands'
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
temp_path = temp_dir / vsix_path.name
|
||||
shutil.copy(vsix_path, temp_path)
|
||||
return temp_path
|
||||
except Exception as e:
|
||||
logger.debug(f'Could not access bundled VSIX: {e}')
|
||||
|
||||
# If bundled VSIX is not available, try to download from GitHub
|
||||
github_vsix = download_latest_vsix_from_github()
|
||||
if github_vsix:
|
||||
return Path(github_vsix)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _attempt_marketplace_install(
|
||||
editor_command: str, editor_name: str, extension_id: str
|
||||
) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user