diff --git a/.serena/project.yml b/.serena/project.yml index c2d3a13e28..88e473847f 100644 --- a/.serena/project.yml +++ b/.serena/project.yml @@ -31,6 +31,7 @@ project_name: "penpot" languages: - clojure - typescript +- rust # the encoding used by text files in the project # For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings @@ -127,3 +128,14 @@ ignored_memory_patterns: [] # The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. # See https://oraios.github.io/serena/02-usage/050_configuration.html#modes added_modes: + +# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). +# Paths can be absolute or relative to the project root. +# Each folder is registered as an LSP workspace folder, enabling language servers to discover +# symbols and references across package boundaries. +# Currently supported for: TypeScript. +# Example: +# additional_workspace_folders: +# - ../sibling-package +# - ../shared-lib +additional_workspace_folders: [] diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index 5034ba5f01..64b0ac1dae 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -185,7 +185,12 @@ ENV CLJKONDO_VERSION=2026.04.15 \ BABASHKA_VERSION=1.12.208 \ CLJFMT_VERSION=0.16.4 \ PIXI_VERSION=0.67.2 \ - GITHUB_CLI_VERSION=2.91.0 + GITHUB_CLI_VERSION=2.91.0 \ + UV_VERSION=0.11.9 \ + UV_TOOL_DIR=/opt/uv/tools \ + UV_TOOL_BIN_DIR=/opt/utils/bin \ + UV_PYTHON_INSTALL_DIR=/opt/uv/python \ + SERENA_VERSION=v1.3.0 RUN set -ex; \ ARCH="$(dpkg --print-architecture)"; \ @@ -309,6 +314,31 @@ RUN set -ex; \ mv /tmp/mc /opt/utils/bin/; \ chmod +x /opt/utils/bin/mc; +# Install uv +RUN set -ex; \ + ARCH="$(dpkg --print-architecture)"; \ + case "${ARCH}" in \ + aarch64|arm64) \ + BINARY_URL="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-aarch64-unknown-linux-musl.tar.gz"; \ + ;; \ + amd64|x86_64) \ + BINARY_URL="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-x86_64-unknown-linux-musl.tar.gz"; \ + ;; \ + *) \ + echo "Unsupported arch: ${ARCH}"; \ + exit 1; \ + ;; \ + esac; \ + curl -LfsSo /tmp/uv.tar.gz ${BINARY_URL}; \ + cd /opt/utils/bin; \ + tar -xf /tmp/uv.tar.gz --strip-components=1; \ + rm -rf /tmp/uv.tar.gz; + +# Install uv-managed tools +RUN set -ex; \ + /opt/utils/bin/uv tool install -p 3.13 \ + "serena-agent@${SERENA_VERSION}" \ + --prerelease=allow; ################################################################################ ## DEVENV BASE @@ -421,6 +451,11 @@ ENV LANG='C.UTF-8' \ JAVA_HOME="/opt/jdk" \ CARGO_HOME="/opt/cargo" \ RUSTUP_HOME="/opt/rustup" \ + UV_TOOL_DIR="/opt/uv/tools" \ + UV_TOOL_BIN_DIR="/opt/utils/bin" \ + UV_PYTHON_INSTALL_DIR="/opt/uv/python" \ + SERENA_HOME="/home/penpot/.serena" \ + SERENA_CONTEXT="claude-code" \ PATH="/opt/jdk/bin:/opt/gh/bin:/opt/utils/bin:/opt/clojure/bin:/opt/node/bin:/opt/imagick/bin:/opt/cargo/bin:$PATH" COPY --from=penpotapp/imagemagick:7.1.2-13 /opt/imagick /opt/imagick @@ -429,6 +464,7 @@ COPY --from=setup-jvm /opt/clojure /opt/clojure COPY --from=setup-node /opt/node /opt/node COPY --from=setup-utils /opt/utils /opt/utils COPY --from=setup-utils /opt/gh /opt/gh +COPY --from=setup-utils /opt/uv /opt/uv COPY --from=setup-rust /opt/cargo /opt/cargo COPY --from=setup-rust /opt/rustup /opt/rustup COPY --from=setup-rust /opt/emsdk /opt/emsdk @@ -444,6 +480,7 @@ COPY files/tmux.conf /root/.tmux.conf COPY files/sudoers /etc/sudoers COPY files/Caddyfile /home/ +COPY files/serena_config.yml /home/serena_config.yml COPY files/selfsigned.crt /home/ COPY files/selfsigned.key /home/ COPY files/start-tmux.sh /home/start-tmux.sh diff --git a/docker/devenv/docker-compose.yaml b/docker/devenv/docker-compose.yaml index 4a680e4e6b..b69cf550db 100644 --- a/docker/devenv/docker-compose.yaml +++ b/docker/devenv/docker-compose.yaml @@ -57,6 +57,10 @@ services: - 4201:4201 - 4202:4202 + # Serena MCP server (agentic mode only) + - ${SERENA_EXTERNAL_PORT:-14281}:14281 + - ${SERENA_DASHBOARD_EXTERNAL_PORT:-14282}:24282 + environment: - EXTERNAL_UID=${CURRENT_USER_ID} # SMTP setup diff --git a/docker/devenv/files/entrypoint.sh b/docker/devenv/files/entrypoint.sh index b6240777e7..e12b062b4d 100755 --- a/docker/devenv/files/entrypoint.sh +++ b/docker/devenv/files/entrypoint.sh @@ -10,7 +10,17 @@ cp /root/.bashrc /home/penpot/.bashrc cp /root/.vimrc /home/penpot/.vimrc cp /root/.tmux.conf /home/penpot/.tmux.conf +# Seed SERENA_HOME with default config on first run +mkdir -p ${SERENA_HOME} +if [ ! -f "${SERENA_HOME}/serena_config.yml" ]; then + cp /home/serena_config.yml "${SERENA_HOME}/serena_config.yml" +fi +chown -R penpot:users ${SERENA_HOME} + chown penpot:users /home/penpot +# we need to be able to install rust-analyzer and possibly other dependencies with rustup +chown -R penpot:ubuntu /opt/rustup + rsync -ar --chown=penpot:users /opt/cargo/ /home/penpot/.cargo/ export JAVA_OPTS="-Djava.net.preferIPv4Stack=true" diff --git a/docker/devenv/files/serena_config.yml b/docker/devenv/files/serena_config.yml new file mode 100644 index 0000000000..d62bad2c79 --- /dev/null +++ b/docker/devenv/files/serena_config.yml @@ -0,0 +1,153 @@ +language_backend: LSP + +# line ending convention to use when writing source files. +# Possible values: "lf" (Unix), "crlf" (Windows), "native" (platform default). +# Note that Serena's own files (e.g. memories and configuration files) always use native line endings. +# This setting can be overridden on a per-project basis in project.yml files. +line_ending: native + +# whether to open a graphical window with Serena's logs. +# This is mainly supported on Windows and (partly) on Linux; not available on macOS. +# If you prefer a browser-based tool, use the `web_dashboard` option instead. +# Further information: https://oraios.github.io/serena/02-usage/060_dashboard.html +# +# Being able to inspect logs is useful both for troubleshooting and for monitoring the tool calls, +# especially when using the agno playground, since the tool calls are not always shown, +# and the input params are never shown in the agno UI. +# When used as MCP server for Claude Desktop, the logs are primarily for troubleshooting. +# Note: unfortunately, the various entities starting the Serena server or agent do so in +# mysterious ways, often starting multiple instances of the process without shutting down +# previous instances. This can lead to multiple log windows being opened, and only the last +# window being updated. Since we can't control how agno or Claude Desktop start Serena, +# we have to live with this limitation for now. +gui_log_window: false + +# whether to start the Serena Dashboard, which provides detailed information on your Serena session, +# the current configuration and furthermore allows some settings to be conveniently modified on the fly. +# We strongly recommend to always enable this option! +# If you want to prevent the Dashboard window from being opened on launch, +# set `web_dashboard_open_on_launch` to false (see below). +# Further information: https://oraios.github.io/serena/02-usage/060_dashboard.html +web_dashboard: true + +# whether to open the Dashboard window/browser tab when Serena starts (provided that web_dashboard is enabled). +# If set to false, you can still open the dashboard manually by clicking on the Serena icon in your system +# tray on Windows and macOS. On Linux, there is no system tray support, so you can only open the dashboard by +# a) telling the LLM to "open the dashboard" (provided that the open_dashboard tool is enabled) or by +# b) manually navigating to http://localhost:24282/dashboard/ in your web browser (actual port +# may be higher if you have multiple instances running; try ports 24283, 24284, etc.) +# See also: https://oraios.github.io/serena/02-usage/060_dashboard.html +web_dashboard_open_on_launch: false + +# defines the interface (application mode) used for the web dashboard (if enabled). +# If empty/null, use platform-dependent default. Otherwise, possible values: +# * browser: the dashboard is opened in the default browser (if `web_dashboard_open_on_launch` is true) +# This is supported on all platforms. +# * app: the dashboard is opened in a separate native-like app window with accompanying tray icon, whose +# lifecycle is tied to the Serena process. +# If `web_dashboard_open_on_launch` is false, the dashboard can be conveniently accessed via the tray icon. +# This is supported on Windows and macOS, but note that on macOS, where tray icons are very visible, +# this may result in too many icons being displayed when using multi-agent setups. +# * tray_manager: use a global tray icon to provide access to the dashboards of all running Serena instances, +# opening the dashboard in browser tabs when selected from the tray menu. +# This is EXPERIMENTAL. It is tested on Windows only. We will establish macOS support, but it is yet untested. +# On Linux, this cannot be universally supported, but it may work in some desktop environments. +web_dashboard_interface: + +# the address the web dashboard will listen on (bind address). +web_dashboard_listen_address: 0.0.0.0 + +# address where JetBrains plugin servers are running (only relevant when using the JetBrains language backend) +jetbrains_plugin_server_address: 127.0.0.1 + +# the minimum log level for the GUI log window and the dashboard (10 = debug, 20 = info, 30 = warning, 40 = error) +log_level: 20 + +# whether to trace the communication between Serena and the language servers. +# This is useful for debugging language server issues. +trace_lsp_communication: false + +# advanced configuration option allowing to configure language server-specific options. +# Maps the language key to the options. +# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. +# No documentation on options means no options are available. +ls_specific_settings: {} + +# list of paths to ignore across all projects. +# Same syntax as gitignore, so you can use * and **. +# These patterns are merged additively with each project's own ignored_paths. +ignored_paths: [] + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# For example, "global/.*" will mark all global memories as read-only. +# You can extend the list on a per-project basis in the project.yml configuration file. +read_only_memory_patterns: [] + +# list of regex patterns for memories to completely ignore. +# Matching memories will not appear in list_memories or activate_project output +# and cannot be accessed via read_memory or write_memory. +# To access ignored memory files, use the read_file tool on the raw file path. +# This is useful for projects with large numbers of archived memory files. +# You can extend the list on a per-project basis in the project.yml configuration file. +# Example: ["_archive/.*", "_episodes/.*"] +ignored_memory_patterns: [] + +# timeout, in seconds, after which tool executions are terminated +tool_timeout: 240 + +# list of tools to be globally excluded +excluded_tools: [] + +# list of optional tools (which are disabled by default) to be included +included_optional_tools: [] + +# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. +# This cannot be combined with non-empty excluded_tools or included_optional_tools. +fixed_tools: [] + +# list of mode names to that are always to be included in the set of active modes +# The full set of modes to be activated is base_modes + default_modes. +# If this is undefined, no base modes are included. +# The project configuration (project.yml) may override this setting. +base_modes: [no-onboarding] + +# list of mode names that are to be activated by default. +# The full set of modes to be activated is base_modes + default_modes. +# These modes can be overridden by the project configuration (project.yml) or through the CLI (--mode). +default_modes: +- interactive +- editing +default_max_tool_answer_chars: 150000 + +# the name of the token count estimator to use for tool usage statistics. +# See the `RegisteredTokenCountEstimator` enum for available options. +# +# By default, a very naive character count estimator is used, which simply counts the number of characters. +# You can configure this to TIKTOKEN_GPT4 to use a local tiktoken-based estimator for GPT-4 (will download tiktoken +# data files on first run), or ANTHROPIC_CLAUDE_SONNET_4 which will use the (free of cost) Anthropic API to +# estimate the token count using the Claude Sonnet 4 tokenizer. +token_count_estimator: CHAR_COUNT + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# (currently only used by LSP-based tools). +# If the budget is exceeded, Serena stops issuing further retrieval requests +# and returns partial info results. +# 0 disables the budget (no early stopping). Negative values are invalid. +# This is an advanced setting that can help alleviate problems with LSP servers +# that have a slow implementation of request_hover (clangd is one of those) +# or with tool calls that find very many symbols. +# Can be overridden in project.yml. +symbol_info_budget: 10 + +# template for the location of the per-project .serena data folder (memories, caches, etc.). +# Supports the following placeholders: +# $projectDir - the absolute path to the project root directory +# $projectFolderName - the name of the project directory +# Default: "$projectDir/.serena" (data stored inside the project directory) +# Example for a central location: "/projects-metadata/$projectFolderName/.serena" +project_serena_folder_location: "$projectDir/.serena" + +# the list of registered project paths (updated automatically). +projects: +- /home/penpot/penpot diff --git a/docker/devenv/files/start-tmux.sh b/docker/devenv/files/start-tmux.sh index 4deeca6801..e9acc165fe 100755 --- a/docker/devenv/files/start-tmux.sh +++ b/docker/devenv/files/start-tmux.sh @@ -47,10 +47,16 @@ if echo "$PENPOT_FLAGS" | grep -q "enable-mcp"; then pnpm run build; popd - tmux new-window -t penpot:4 -n 'mcp server' + tmux new-window -t penpot:4 -n 'mcp' tmux select-window -t penpot:4 tmux send-keys -t penpot 'cd penpot/mcp' enter C-l tmux send-keys -t penpot './scripts/start-mcp-devenv' enter fi +if [ "${SERENA_ENABLED:-false}" = "true" ]; then + tmux new-window -t penpot:5 -n 'serena' + tmux select-window -t penpot:5 + tmux send-keys -t penpot "serena start-mcp-server --transport streamable-http --port 14281 --project penpot --context ${SERENA_CONTEXT} --host 0.0.0.0" enter +fi + tmux -2 attach-session -t penpot diff --git a/manage.sh b/manage.sh index eb87d41b14..332febdfe8 100755 --- a/manage.sh +++ b/manage.sh @@ -108,13 +108,57 @@ function log-devenv { } function run-devenv-tmux { + local extra_env_args=() + + while [[ $# -gt 0 ]]; do + case "$1" in + -e) + extra_env_args+=(-e "$2"); shift 2;; + -e*) + extra_env_args+=(-e "${1#-e}"); shift;; + *) + shift;; + esac + done + if [[ ! $(docker ps -f "name=penpot-devenv-main" -q) ]]; then start-devenv echo "Waiting for containers fully start (5s)..." sleep 5; fi - docker exec -ti penpot-devenv-main sudo -EH -u penpot PENPOT_PLUGIN_DEV=$PENPOT_PLUGIN_DEV /home/start-tmux.sh + docker exec -ti \ + "${extra_env_args[@]}" \ + penpot-devenv-main sudo -EH -u penpot PENPOT_PLUGIN_DEV=$PENPOT_PLUGIN_DEV /home/start-tmux.sh +} + + +function run-devenv-agentic { + local serena_context="desktop-app" + local serena_external_port="14281" + local serena_dashboard_external_port="14282" + + while [[ $# -gt 0 ]]; do + case "$1" in + --serena-context) + serena_context="$2"; shift 2;; + *) + shift;; + esac + done + + if [[ ! $(docker ps -f "name=penpot-devenv-main" -q) ]]; then + SERENA_EXTERNAL_PORT="$serena_external_port" \ + SERENA_DASHBOARD_EXTERNAL_PORT="$serena_dashboard_external_port" \ + start-devenv + echo "Waiting for containers fully start (5s)..." + sleep 5; + fi + + run-devenv-tmux \ + -e SERENA_ENABLED=true \ + -e SERENA_CONTEXT="$serena_context" \ + -e PENPOT_FLAGS="${PENPOT_FLAGS} enable-mcp" } function run-devenv-shell { @@ -358,6 +402,9 @@ function usage { echo "- stop-devenv Stops the development oriented docker compose service." echo "- drop-devenv Remove the development oriented docker compose containers, volumes and clean images." echo "- run-devenv Attaches to the running devenv container and starts development environment" + echo " Optional -e flags are forwarded to 'docker exec' (e.g. -e MY_VAR=value)." + echo "- run-devenv-agentic Like run-devenv but with additional processes for agentic development enabled." + echo " Options: --serena-context CONTEXT (default: desktop-app)" echo "- run-devenv-shell Attaches to the running devenv container and starts a bash shell." echo "- isolated-shell Starts a bash shell in a new devenv container." echo "- log-devenv Show logs of the running devenv docker compose service." @@ -405,6 +452,9 @@ case $1 in run-devenv) run-devenv-tmux ${@:2} ;; + run-devenv-agentic) + run-devenv-agentic ${@:2} + ;; run-devenv-shell) run-devenv-shell ${@:2} ;;