mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 04:16:34 +00:00
Merge pull request #1539 from oraios/launch-jetbrains
Add configuration option `jetbrains_launch_command`
This commit is contained in:
6 files changed
+58
-11
No files matched your search
@@ -11,6 +11,10 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
processed by the Svelte LS instead of the TypeScript LS.
|
||||
- Improve quoting of arguments in shell executions
|
||||
|
||||
* JetBrains:
|
||||
- Add configuration option `jetbrains_launch_command`, allowing Serena to spawn IDE instances automatically
|
||||
upon project activation
|
||||
|
||||
* Dashboard:
|
||||
- Make list of trusted hosts configurable, fixing host validation introduced in v1.5.2 allowing only
|
||||
default local hostnames, effectively preventing remote connections
|
||||
|
||||
@@ -84,7 +84,7 @@ language_backend: JetBrains
|
||||
|
||||
Note that the file might not exist yet if you never executed Serena before.
|
||||
|
||||
**Per-Server Instance Configuration**.
|
||||
**Per-Instance Configuration**.
|
||||
The configuration setting in the global config file can be overridden on a
|
||||
per-instance basis by providing the arguments `--language-backend JetBrains` when
|
||||
launching the Serena MCP server.
|
||||
@@ -121,8 +121,12 @@ You will also notice that your client will use the JetBrains-specific tools like
|
||||
|
||||
Having installed the plugin in your IDE and having configured Serena to use the JetBrains backend,
|
||||
the general workflow is simple:
|
||||
|
||||
1. Open the project you want to work on in your JetBrains IDE.
|
||||
Note that the project must be appropriately set up in your IDE, i.e. symbol lookups for all relevant programming languages and frameworks should work in the IDE.
|
||||
Note that the project must be appropriately set up in your IDE, i.e. symbol lookups for all relevant programming languages and frameworks should work in the IDE.
|
||||
|
||||
You can optionally make Serena open an IDE instance for your project root folder automatically upon project activation, allowing you to skip this step for a project that was previously set up correctly.
|
||||
To enable this, configure `jetbrains_launch_command` in [Serena's global configuration file](global-config) appropriately.
|
||||
2. Activate the project's root folder as a project in Serena (see [Project Creation](project-creation-indexing) and [Project Activation](project-activation)).
|
||||
3. Start using Serena's tools as usual.
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import multiprocessing
|
||||
import os
|
||||
import platform
|
||||
import signal
|
||||
import subprocess
|
||||
import threading
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable, Iterator, Sequence
|
||||
@@ -40,6 +41,7 @@ from serena.config.serena_config import (
|
||||
ToolInclusionDefinition,
|
||||
)
|
||||
from serena.dashboard import SerenaDashboardAPI, SerenaDashboardTrayManager, SerenaDashboardViewer, open_url_in_browser
|
||||
from serena.jetbrains import jetbrains_plugin_client
|
||||
from serena.ls_manager import LanguageServerManager
|
||||
from serena.memories.memory_manager import MemoryManager
|
||||
from serena.project import Project
|
||||
@@ -60,6 +62,7 @@ from serena.util.gui import system_has_usable_display
|
||||
from serena.util.inspection import iter_subclasses
|
||||
from serena.util.logging import MemoryLogHandler
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.util import subprocess_util
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from serena.gui_log_viewer import GuiLogViewer
|
||||
@@ -1165,6 +1168,25 @@ class SerenaAgent:
|
||||
if self.get_language_backend().is_lsp():
|
||||
self.issue_task(init_language_server_manager)
|
||||
|
||||
def init_jetbrains_ide() -> None:
|
||||
assert self.serena_config.jetbrains_launch_command is not None
|
||||
try:
|
||||
client = jetbrains_plugin_client.JetBrainsPluginClient.from_project(project, log_warning=False)
|
||||
log.info("Found Serena JetBrains Plugin server: %s", client)
|
||||
except jetbrains_plugin_client.ServerNotFoundError:
|
||||
log.info("Serena JetBrains Plugin server not found for project %s", project.project_name)
|
||||
if self.serena_config.jetbrains_launch_command:
|
||||
cmd = subprocess_util.convert_shell_cmd([self.serena_config.jetbrains_launch_command, project.project_root])
|
||||
log.info("Launching IDE with command: %s", cmd)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
log.error(f"Failed to launch JetBrains IDE: {stderr.decode('utf-8')}")
|
||||
|
||||
# for JetBrains mode, search for plugin server and spawn IDE if not found and enabled
|
||||
if self.get_language_backend().is_jetbrains():
|
||||
self.issue_task(init_jetbrains_ide)
|
||||
|
||||
if self._project_activation_callback is not None:
|
||||
self._project_activation_callback()
|
||||
|
||||
|
||||
@@ -722,6 +722,10 @@ class SerenaConfig(SharedConfig, ModeSelectionDefinitionWithBaseModes):
|
||||
web_dashboard_listen_address: str = "127.0.0.1"
|
||||
web_dashboard_trusted_hosts: list[str] = field(default_factory=lambda: ["127.0.0.1", "localhost"])
|
||||
jetbrains_plugin_server_address: str = "127.0.0.1"
|
||||
jetbrains_launch_command: str | None = None
|
||||
"""
|
||||
JetBrains IDE launch command, which can be used to auto-start an IDE instance on demand.
|
||||
"""
|
||||
tool_timeout: float = DEFAULT_TOOL_TIMEOUT
|
||||
|
||||
token_count_estimator: str = RegisteredTokenCountEstimator.CHAR_COUNT.name
|
||||
|
||||
@@ -105,7 +105,12 @@ class JetBrainsPluginClientManager:
|
||||
futures.append(future)
|
||||
return futures
|
||||
|
||||
def find_client(self, project_root: Path) -> "JetBrainsPluginClient":
|
||||
def find_client(self, project_root: Path, log_warning: bool = True) -> "JetBrainsPluginClient":
|
||||
"""
|
||||
:param project_root: the project root path to find a plugin instance for
|
||||
:param log_warning: whether to log a warning if no matching plugin instance is found
|
||||
:return: the instance
|
||||
"""
|
||||
plugin_paths_found = []
|
||||
for future in self._submit_scan():
|
||||
client = future.result()
|
||||
@@ -114,12 +119,13 @@ class JetBrainsPluginClientManager:
|
||||
elif client.project_root is not None:
|
||||
plugin_paths_found.append(client.project_root)
|
||||
|
||||
log.warning(
|
||||
"Searched for Serena JetBrains plugin service for project at %s but found no matching service. "
|
||||
"Found plugin instances for the following project paths: %s",
|
||||
project_root,
|
||||
plugin_paths_found,
|
||||
)
|
||||
if log_warning:
|
||||
log.warning(
|
||||
"Searched for Serena JetBrains plugin service for project at %s but found no matching service. "
|
||||
"Found plugin instances for the following project paths: %s",
|
||||
project_root,
|
||||
plugin_paths_found,
|
||||
)
|
||||
raise ServerNotFoundError(
|
||||
f"Found no Serena service in a JetBrains IDE instance for the project at {project_root}. "
|
||||
"STOP. Do not attempt any other tools or workarounds. Ask the user to open this folder as a project in a JetBrains IDE "
|
||||
@@ -219,7 +225,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
return ["_port", "project_root", "_plugin_version"]
|
||||
|
||||
@classmethod
|
||||
def from_project(cls, project: Project) -> Self:
|
||||
def from_project(cls, project: Project, log_warning: bool = True) -> Self:
|
||||
resolved_path = Path(project.project_root).resolve()
|
||||
|
||||
if cls._last_port is not None:
|
||||
@@ -227,7 +233,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
if client.matches(resolved_path):
|
||||
return client
|
||||
|
||||
client = JetBrainsPluginClientManager().find_client(resolved_path)
|
||||
client = JetBrainsPluginClientManager().find_client(resolved_path, log_warning=log_warning)
|
||||
cls._last_port = client._port
|
||||
return client
|
||||
|
||||
|
||||
@@ -80,6 +80,13 @@ web_dashboard_trusted_hosts:
|
||||
# address where JetBrains plugin servers are running (only relevant when using the JetBrains language backend)
|
||||
jetbrains_plugin_server_address: 127.0.0.1
|
||||
|
||||
# command used to launch a JetBrains IDE on demand (only relevant when using the JetBrains language backend)
|
||||
# If this is non-empty and, at project activation, the Serena JetBrains Plugin server instance corresponding
|
||||
# to the project is not found, use this command to spawn a new instance.
|
||||
# Specifically, if this is <cmd>, then `<cmd> <projectDir>` is launched.
|
||||
# Provide the full path to the executable/script (e.g., "/usr/bin/idea" or "C:/Users/bob/AppData/Local/JetBrains/Toolbox/scripts/idea.cmd").
|
||||
jetbrains_launch_command:
|
||||
|
||||
# the minimum log level for the GUI log window and the dashboard (10 = debug, 20 = info, 30 = warning, 40 = error)
|
||||
log_level: 20
|
||||
|
||||
|
||||
Reference in new issue
Block a user