Commit Graph
3364 Commits
Author SHA1 Message Date
Dominik Jain 05603b2706 Add configuration facade (cfg) with get_current_config and open_dashboard
Introduce ConfigApi, exposing Serena's configuration and session state: get_current_config and
open_dashboard (both non-editing). The corresponding tools delegate to the API via ConfigApiMixin.

As on the tool side, opening the dashboard is only offered if the dashboard is enabled and not
opened automatically; the condition is shared (_is_dashboard_openable) and applied to the API scope
via a NamedApiInclusionDefinition, the API-side counterpart of NamedToolInclusionDefinition.
2026-09-15 12:50:44 +02:00
Dominik Jain 6716193d71 Render prompts according to the agent interface
Prompt parameters (available tools/markers and the tool name mapping) are now computed per agent
interface (SerenaAgent.PromptParams). In REPL mode, the available tools comprise the exposed tools
and the enabled facade methods, and the tool name mapping resolves tool names to the qualified names
of the corresponding facade methods (e.g. `lsp.find_symbol`), such that prompts refer to operations
as they are used in REPL code. The parameters are re-computed whenever the active tools change.

FacadeMethod refers to its parent facade and provides facade_name and qualified_name; its name is
taken from its info. Prompt templates use the tool name mapping consistently (fixing a template
syntax error in the editing mode) and use interface-neutral wording.
2026-09-15 12:50:44 +02:00
Dominik Jain 337d545c4b Add agent_interface setting selecting the tool or REPL interface
Introduce AgentInterface (tools/REPL) as a setting in the global configuration, overridable per
project (resolution: project > global > default "tools") and via the CLI option --agent-interface.
The interface is fixed for the session, like the language backend.

In REPL mode, the set of exposed tools is fixed: the REPL tool, initial_instructions and (unless in a
single-project session) activate_project. Tool inclusion/exclusion definitions do not apply in REPL
mode, as they pertain to the tool interface; the REPL is configured via API inclusions/exclusions.
The REPL tool is optional in tool mode.

SerenaAgent.is_single_project records whether the session is a single-project session.
2026-09-15 12:50:44 +02:00
Dominik Jain e7aa6a74e1 Add repl memory documenting the REPL's structure, principles and availability policy 2026-09-15 12:50:44 +02:00
Dominik Jain 07b6831c70 Record the correspondence between API methods and tools
FacadeMethodInfo gains corresponding_tool (the tool class offering the same functionality) and
get_corresponding_tool_name, and every API method with a tool counterpart names it in its
facade_method decorator. This enables applying tool-level exclusions to API methods and rendering
prompt conditions based on tools.

Since the API modules now refer to the tool classes, the tools import the APIs locally (in the
mixins' _api methods), and the symbol tools' symbol_dict_grouper attributes become properties.
2026-09-15 12:50:44 +02:00
Dominik Jain a46a465773 Add shell facade (shell) for shell command execution
Introduce ShellApi with the single editing operation execute_shell_command, which returns a
ShellCommandOutput exposing stdout, stderr, return code and working directory to code and rendering
as JSON as before. Keeping shell command execution in its own facade makes it a natural unit for
exclusion. The shell command tool delegates to the API via ShellApiMixin; the shell facade is always
part of the REPL.
2026-09-15 12:50:44 +02:00
Dominik Jain 5f129628d9 Add file system facade (fs); create_text_file moves there from edit
Introduce FsApi, exposing operations on the project's files as units: read_file, create_text_file,
list_dir, find_file and search_for_pattern. The boundary to the edit facade, which modifies content
within existing files, is stated in the facade description. Results expose their data to code
(FileContent, DirectoryListing, PatternMatches) and render as before; the pattern search's
shortening ladder moves from the tool into PatternMatchesRenderer.

The file tools delegate to the API via FsApiMixin. The fs facade is always part of the REPL.
2026-09-15 12:50:44 +02:00
Dominik Jain c0e74c7d7e Describe facades by domain rather than by listing operations
The method list accompanies every facade description, so naming operations in it was redundant.
2026-09-15 12:50:44 +02:00
Dominik Jain 8e4d68cd40 Add memory facade (mem) including onboarding
Introduce MemoryApi, exposing the memory operations list_memories, read_memory, write_memory,
edit_memory, rename_memory and delete_memory (the latter four marked as editing operations) as well
as onboarding, which provides the onboarding instructions. list_memories returns a MemoryList, which
exposes the (writable and read-only) memory names to code and renders as JSON.

The memory tools and the onboarding tool delegate to the API via MemoryApiMixin; the onboarding tool
retains its check for the availability of the memory writing tool. The mem facade is always part of
the REPL.

The modes no-onboarding, no-memories and benchmark exclude the corresponding APIs (mem.onboarding,
or the mem facade as a whole), mirroring their tool exclusions.
2026-09-15 12:50:44 +02:00
Dominik Jain d9cda96725 Add instructions on commit messages 2026-09-15 12:50:44 +02:00
Dominik Jain f38f12915b Enable ty's unresolved-import rule
Broken first-party imports previously went undetected, since the rule was globally disabled to
accommodate optional extras and platform-specific modules. These are now handled narrowly:
per-file overrides for the agno integration (optional extra, not installed in CI) and for the
pywebview integration (several macOS-only imports), and an inline suppression for the single
macOS-only import in the dashboard.
2026-09-15 12:50:44 +02:00
Dominik Jain fee1aef934 Rename package facades to repl and API modules to *_api 2026-09-15 12:50:44 +02:00
Dominik Jain 66ed46bef4 Add editing facade (edit) covering the backend-independent edit operations
Introduce EditApi as the facade for editing operations which depend
only on the code editor abstraction and thus work with any language
backend: create_text_file, replace_content, replace_in_files, the
optional line-level operations delete_lines, replace_lines and
insert_at_line, and the symbol-level operations replace_symbol_body,
insert_after_symbol and insert_before_symbol (moved from LspApi, which
retains the LSP-specific rename_symbol and safe_delete_symbol).

replace_in_files builds on MultiFileReplacement: a dry run returns a
ReplacementPreview, which exposes the occurrences to code and renders
the listing of prospective changes; rejections raise a ValueError
carrying the listing where applicable.

FacadeApi gains a backend-agnostic _create_code_editor; the LSP API's
retriever-based factory is renamed to _create_ls_code_editor. The
editing tools (file and symbol level) delegate to EditApi via
EditApiMixin, retaining only the diagnostics context. The edit facade
is always part of the REPL.
2026-09-15 12:50:43 +02:00
Dominik Jain 8ace53c3a1 Extract multi-file replacement logic from ReplaceInFilesTool
Introduce MultiFileReplacement (in serena.util.text_utils, alongside
MultiFileContentReplacer), which owns the logic previously spread over
the tool's private methods: resolving the files in scope (via the
project's file collection and glob filtering, which the tool had
re-implemented), finding occurrences, resolving occurrence ids with
diagnostics, the safety checks for blind application (no matches,
expected count, ambiguous matches), rendering the listing of
prospective changes and applying the selected occurrences. Rejections
are signalled via ReplacementRejectedError, which indicates whether
the listing should accompany the message, leaving presentation
(listing, length limit, diagnostics context) to the tool.

EditedFileContext moves from tools_base to code_editor, where it
belongs (re-exported from serena.tools); Project.create_file_collection
is now public; Tool gains _resolve_max_answer_chars.
2026-09-15 12:50:43 +02:00
Dominik Jain 9b0f6cf97a Restore symbol_dict_grouper attributes on the symbol tools
The attribute is the tools' public handle for disabling grouping (disabled_context()),
used by the health check and tests.
2026-09-15 12:50:43 +02:00
Dominik Jain eabc7e60d6 Add facade method metadata and API scope configuration for the REPL
Facade methods are now declared explicitly via the facade_method
decorator, which attaches FacadeMethodInfo (optional, beta, can_edit)
mirroring the tool markers; undecorated methods are never exposed.
All LspApi and JetBrainsApi methods are decorated accordingly
(JetBrains methods are non-optional, as the facade only exists with
the JetBrains backend).

Which facades/methods are enabled is determined by an ApiScope, which
is built by applying ApiInclusionDefinitions (included_apis,
excluded_apis, referencing facades or facade methods such as "lsp" or
"lsp.find_symbol") from the global configuration, the context, the
active modes and the project configuration, in that order. Optional
methods and all methods of an excluded facade must be included
explicitly; other methods are enabled unless excluded. For read-only
projects, editing methods are excluded. The entrypoint omits facades
which are not enabled.

The REPL is re-created whenever the active tools are updated (mode
switch, project activation), as it depends on the same configuration.
The new settings are read from project.yml and documented in all
configuration templates.
2026-09-15 12:50:43 +02:00
Dominik Jain 91c2ec8dc2 Add remaining LSP operations to the lsp facade; tools delegate to LspApi
LspApi now covers all language server-backed operations:
restart_language_server, get_symbols_overview, find_symbol,
find_referencing_symbols, find_implementations, find_declaration,
get_diagnostics_for_file, get_diagnostics_for_symbol,
replace_symbol_body, insert_after_symbol, insert_before_symbol,
rename_symbol and safe_delete_symbol.

Result objects carry their rendering policy:
* LspSymbolCollectionRenderer was generalised (symbol_dicts_,
  child_inclusion_predicate) and is reused by find_implementations
* LspSymbolsOverviewRenderer renders a file's overview with the
  depth-0/kind-count shortening ladder
* LspSymbol/LspSymbolRenderer represent a single symbol
  (find_declaration), preserving the dict output shape
* LspReferenceCollection with its renderer (context lines, per-file
  counts, total count)
* LspDiagnostics wrapping GroupedDiagnostics

The symbol tools are now thin adapters which delegate to the API via
the LspApiMixin (the JetBrains tools use JetBrainsApiMixin
analogously, replacing the intermediate tool base class). Editing
tools retain the DiagnosticsContext wrapper, which the API does not
use; DiagnosticsContext moved to serena.lsp.lsp_diagnostics and is
created via EditingToolWithDiagnostics.diagnostics_context.

SUCCESS_RESULT moved to serena.facades.facade (the API cannot import
from serena.tools without an import cycle); serena.tools re-exports it.
The project health check in the CLI uses LspApi directly instead of
tool internals. iter_subclasses now yields each class once.
2026-09-15 12:50:43 +02:00
Dominik Jain eb53a4cee4 Add JetBrains facade (jb) covering all JetBrains tools
Introduce JetBrainsApi as the second facade implementation, exposing
all JetBrains IDE-backed operations to the REPL: find_symbol,
find_referencing_symbols, get_symbols_overview, get_type_hierarchy,
find_declaration, find_implementations, rename, move, safe_delete,
inline_symbol, run_inspections, list_inspections, debug_eval and
debug_eval_info (which provides the debug REPL usage information
otherwise obtained via the serena_info tool).

Result objects carry their rendering policy, following the LSP facade:
* JetBrainsSymbolCollection with renderers for symbol searches
  (grouped JSON, falling back to identifiers) and references (falling
  back to per-file counts and the total count)
* JetBrainsSymbolsOverview with the compact overview format and its
  shortening ladder
* JsonObject, a new general-purpose representable for plain JSON
  results with length limiting

The JetBrains tools now delegate to the API via a common JetBrainsTool
base, retaining only transport concerns (input sanitisation, the
wildcard-to-overview convenience of the find symbol tool), so that
both surfaces share one implementation. The agent adds the facade to
the REPL when the JetBrains backend is active.

serena_config imported JetBrainsPluginClient through a transitive
re-export from jetbrains_tools; it now imports it from its module.
2026-09-15 10:27:45 +02:00
Dominik Jain 2c9640c3ad Add REPL-based interaction paradigm with a first facade (lsp.find_symbol)
Introduce an alternative to individual tool calls: a single tool
(serena_repl) executes Python code against an entrypoint object `s`,
which exposes Serena's functionality through facades. This lets the
LLM compose operations, filter results in code and return only what
it needs, keeping intermediate data out of the context window.

Facades (serena.facades):
* FacadeApi: base class for implementations. Member naming determines
  LLM visibility: regular names are LLM-facing, a trailing underscore
  marks members that are public within Serena but never exposed to the
  LLM, a leading underscore is private.
* Facade: indirection over a FacadeApi instance (Facade.from_api),
  holding one FacadeMethod per LLM-facing method, each of which can be
  enabled or disabled independently; only enabled methods are
  accessible from REPL code and included in the documentation.
* SerenaRepl/SerenaReplEntrypoint: execute code as the body of a
  function (`return` defines the result; a single expression is
  evaluated directly), render the result via Representable and
  report errors with the line within the submitted code. Progressive
  disclosure via s.info(): the tool description and s.info() list the
  facades with their method names only; s.info("<facade>") and
  s.info("<facade>.<method>") provide signatures together with
  docstrings, never signatures alone.
* Representable/Renderer: result objects carry their rendering policy.
  Output parameters are passed at retrieval time so that they are
  inherited by derived results.

First facade: LspApi with find_symbol, returning an LspSymbolCollection
which renders as the familiar JSON (with grouping and progressive
shortening) while exposing the underlying symbols to code.
FindSymbolTool now delegates to LspApi, so both surfaces share one
implementation. Length limiting and JSON output were moved from Tool
into TextOutputUtils so that facades can use them.

The agent creates the REPL lazily (get_repl) and resets it on project
activation. The tool is marked beta.

Also fixes pre-existing type errors (get_tool return type, invariant
list annotations in symbol_tools, test stubs) found on the way.
2026-09-15 10:27:45 +02:00
Dominik Jain 8fc68d4c6e Set version to v2.0.0.dev0 2026-09-15 10:27:45 +02:00
Dominik Jain 6da423c70a Add dev command to bump_version and make its interface explicit
bump_version could previously only create releases. It now provides two
subcommands, and the mutually exclusive --major/--minor/--patch flags (as
well as the explicit --version option) are replaced by a positional
argument, which cannot be misused:

    bump_version.py release <current|major|minor|patch>
    bump_version.py dev <major|minor|patch>

`dev` bumps the version to a new .dev0 version and commits it as
"Set version to vX" without creating a tag or touching the changelog. This
allows work on main to target a new minor/major version independently of a
release.

Because a .dev0 version no longer necessarily reserves the next patch
version, `release` now takes the target "current", which releases the
version reserved by the current .dev version (the usual case), whereas
major/minor/patch bump beyond it. The former special case of not
incrementing the patch version is thereby removed; `release patch` now
increments the patch version as its name suggests.

`release current` fails if the current version is not a development
version, in which case there is no reserved version to release.
2026-09-15 10:27:45 +02:00
Dominik Jain 18fa47bfcc Merge branch 'gpl' 2026-09-14 21:35:06 +02:00
Dominik Jain 6707cd9b7e Introduce component-based licensing: Serena GPL-3.0-or-later, SolidLSP MIT
The repository is licensed per component. SolidLSP (src/solidlsp,
test/solidlsp, test/resources) remains MIT-licensed and independently
reusable; the Serena application (src/serena, src/interprompt, scripts,
test/serena, docs) is licensed under GPL-3.0-or-later starting with the v2
licensing transition. The change is not retroactive: all releases and
commits up to v1.7.0 / 74c38a65 (tag mit-final) remain available under MIT.

Since MIT is GPL-compatible, a distribution combining both (such as the
serena-agent package) is as a whole subject to GPL-3.0-or-later, while the
SolidLSP files themselves stay MIT and can be extracted and used separately
under MIT terms. The distribution metadata therefore declares
GPL-3.0-or-later, with both license texts shipped alongside it.

Serena originally began under the GPL (v2) and was switched to MIT in
May 2025 following community requests. We consider that change a mistake;
the substantial changes in v2 make this the appropriate time to revert it.
We want the best version of Serena to remain free.

Changes:
* LICENSE is now the licensing overview; canonical license texts live in
  LICENSES/ (MIT.txt is the previous LICENSE verbatim, GPL-3.0-or-later.txt
  is the unmodified FSF text)
* pyproject.toml declares the PEP 639 license expression
  "GPL-3.0-or-later" and bundles LICENSE and LICENSES/* as license files;
  the deprecated MIT classifier is dropped and flake.nix declares gpl3Plus;
  README has per-component license badges and a License section
* SPDX-License-Identifier headers in all Python sources under src/ and
  scripts/, added by the new idempotent scripts/add_spdx_headers.py, which
  gen_prompt_factory.py also uses to keep the header on the generated
  module; existing third-party notices are preserved
* CLA.md: Contributor License Agreement (contributor retains copyright;
  grants a perpetual, irrevocable license including relicensing under any
  terms, incl. proprietary/commercial; patent grant; authority
  representations), to be enforced repository-wide via cla-assistant.io
* CONTRIBUTING.md, PR template and a new docs page explain the licensing
  boundary and the CLA workflow
2026-09-14 21:33:18 +02:00
Dominik Jain 74c38a65f0 Require issue to be real 2026-09-14 17:56:23 +02:00
Dr. Dominik Jain 403ad0a562 Merge pull request #1988 from oraios/ls-registry
SolidLSP: Add language server registry, supporting externally provided implementations
2026-09-12 23:16:52 +02:00
Dominik Jain 283140e7ae Refactor external language server registration
* Apply object-oriented design
* Establish common interface via protocol LanguageServerIdLike
* Move all registration concerns to LanguageServerRegistry
2026-09-12 15:15:34 +02:00
Arek GladkiandArkadiusz Gładki 701e7c843f Fix: health-check reported success after reference search failed (#1998)
`project health-check` runs three tools but only two of them can fail the check: an
exception from `FindReferencingSymbolsTool` was caught and logged as a warning, while
the verdict tested `find_symbol_data` alone. The command therefore printed
"Health check passed - All tools working correctly" and exited 0 on a project whose
reference search had just blown up - the one signal a health check exists to give.

Co-authored-by: Arkadiusz Gładki <biosmoothly@gmail.com>
2026-09-08 13:26:10 +02:00
Dominik Jain c1ca4324d1 Improve docstring 2026-09-08 11:44:56 +02:00
Dominik Jain d645bbb0e1 Update AGENTS.md and CLAUDE.md
Add instructions that allow agents not using Serena to get at
least the most essential information
2026-09-08 11:32:56 +02:00
GuddXzyandGuddXzy 2d2e87763a fix: disable automatic type acquisition in TypeScript backends (#1990)
* fix: disable automatic type acquisition in TypeScript backends

* fix: use shared initialization builder for VTS

Follow review guidance to apply shallow per-key overrides without restoring the ATA default after a user replaces the typescript block. Preserve the legacy settings alias, document the behavior, and cover canonical-key precedence.

---------

Co-authored-by: GuddXzy <267062192+GuddXzy@users.noreply.github.com>
2026-09-08 11:17:35 +02:00
Dominik Jain 9f9db76622 Fix document symbol caching for language servers that post-process symbols
Caching happened in the base implementation before subclass overrides could
post-process the result, so an override's work was either never cached or,
if it mutated in place, re-applied to cached output on every hit.

Restructure both symbol caches so that they wrap the subclass logic:
subclasses now post-process via dedicated hooks (`_request_raw_document_symbols`
and `_build_document_symbols_from_raw_symbols`), and the cached value is
the fully processed result. Cache versions are bumped where the cached
content changes as a consequence.
2026-09-06 13:51:53 +02:00
Amir Fathi be609b6257 fix(kotlin): give concurrent Serena instances independent LSP storage
Two Serena instances activating the same project concurrently launched
their Kotlin LSP processes against the same on-disk index storage
location (both the modern launcher's --system-path arg and the legacy
initializationOptions.storagePath, hardcoded to None), so the second
instance's requests were repeatedly cancelled by the first instance's
server.

DependencyProvider now claims that storage directory with a
non-blocking file lock held for the process's lifetime. A single
instance, including across restarts, still gets the same directory
and keeps its cache; a second concurrent instance falls back to a
directory of its own instead of contending for the first one's.

Fixes #1966
2026-09-06 11:50:21 +02:00
Dominik Jain 7cde558158 Remove test_jetbrains_launch_coordinator 2026-09-06 11:24:20 +02:00
Vitaly Ruhl 6000f16680 feat(solidlsp): prototype registrable language server adapters 2026-09-05 12:36:53 +02:00
xor 13ac8c5b1d SolidLSP: correct the position returned by insert_text_at_position (#1842)
insert_text_at_position returns the position of the end of the inserted text.
That position was computed by _get_updated_position_from_line_and_column_and_edit,
which steps the inserted text in isolation and adds the resulting line/column
delta to the start position.

An insertion is not independent of its surroundings. Under the LSP newline
definition adopted in 9208a3ae, a "\n" inserted directly after an existing "\r"
merges with it into a single "\r\n" sequence, so the text gains no line while the
isolated arithmetic still counts one:

    insert_text_at_position("\r", 1, 0, "\n")    -> ("\r\n", 2, 0); actual (1, 0)
    insert_text_at_position("x\ry", 1, 0, "\n")  -> ("x\r\ny", 2, 0); actual (1, 0)
    insert_text_at_position("a\r", 2, 0, "X")    -> ("a\r\nX", 2, 1); actual (1, 1)

The third case reaches the same fault through the one-line-past-EOF branch, which
prepends a "\n" that then merges with the trailing "\r". The converse interaction
was wrong too: inserting between the "\r" and the "\n" of a "\r\n" splits it, and
the isolated arithmetic reported (0, 2) -- a column on a line the split had just
emptied. In every case the resulting text was correct; only the position was wrong.

9208a3ae centralised line/column computation on TextStepper and reimplemented the
TextUtils methods on it. This helper was rebased onto TextStepper in that commit
but kept its original shape: it steps one string, and the string it steps is the
insertion rather than the result. Once a newline can be formed by two adjacent
characters, no computation over the inserted text alone can be correct.

The position is now determined from the resulting text via get_line_col_from_index,
the same function that resolves positions everywhere else, which removes the last
computation in TextUtils that did not go through the centralised path. The helper
had no other callers and is deleted, along with the line/col adjustment in the
past-EOF branch that existed only to feed it.

The column is clamped to the end of the text before both the splice and the
derivation. This is not a new tolerance: the splice already clamped implicitly
(text[:i] with i > len(text) yields the whole text), so an out-of-range column has
always appended successfully. Making the clamp explicit keeps the position derived
from the same index the splice used; without it, deriving from the result would
newly raise for input that previously worked.

Columns are offsets into the Python string (code points), which the docstring now
states. LSP columns are UTF-16 code units and nothing converts between the two at
the boundary -- a real defect, but a pre-existing and separate one: the previous
arithmetic did not preserve UTF-16 units either, since it added a code-point length
to a code-unit column and so produced a value in neither unit.

    "\U0001f600" + "\U0001f600" at column 2
        old (0, 3); UTF-16 (0, 4); code points (0, 2)

Seven regression tests cover the boundary, mid-document and past-EOF merges, the
newline split, an out-of-range column, a column past a non-BMP character, and an
unaffected "\n"-terminated control. The six that pin changed behaviour were each
verified to fail before the change; the control passes either way.
2026-09-04 13:09:55 +02:00
Dominik Jain 801a388c2b Remove unnecessary platform restrictions in language servers
Platform checks in the following language servers are affected:
* Elixir Tools
* Intelephense
* Perl
* TypeScript
* VTS
2026-09-03 18:35:07 +02:00
Scott McLeod bcb3fc74ff Detect FreeBSD as a platform (#1947)
Language server initialization failed on FreeBSD with "Unknown platform" as there was no mapping for FreeBSD.
2026-09-03 17:15:10 +02:00
ef30801377 fix(config): persist removed registered projects (#1925)
Fixes regression introduced in unreleased commit 8a4d116

Co-authored-by: Yu-0312 <2.66498311e+08+Yu-0312@users.noreply.github.com>
Co-authored-by: Dr. Dominik Jain <dominik.jain@oraios-ai.de>
2026-09-03 15:54:09 +02:00
MaxandYu-0312 24940a1560 fix(process): reap language server descendants (#1918)
* fix(process): reap language server descendants

* fix(process): preserve descendant snapshot for kill fallback

* fix(process): share termination timeout deadline

* fix(process): reap descendants in process-group cleanup

* fix(process): reap leader after descendant kill timeout

---------

Co-authored-by: Yu-0312 <2.66498311e+08+Yu-0312@users.noreply.github.com>
2026-09-03 15:28:05 +02:00
MaxandYu-0312 6f86ae308e fix(solidity): isolate Hardhat state on macOS (#1910)
* fix(solidity): isolate Hardhat state on macOS

---------

Co-authored-by: Yu-0312 <2.66498311e+08+Yu-0312@users.noreply.github.com>
2026-09-03 15:21:15 +02:00
Amir Fathi 14f1a3ce11 fix(memories): stop losing memory content on an interrupted write (#1969)
* fix(memories): stop losing memory content on an interrupted write

save_memory() and edit_memory() wrote the memory file with a plain
open(path, "w") followed by f.write(content). That truncates the file
before the new content is complete, so a crash, an OOM kill, or a
disk-full error partway through the write can leave the file empty or
holding a stale tail instead of either the old or the new content.

Add write_file_atomic() to util/file_system.py: it writes to a temp
file in the same directory, then os.replaces it into place, with the
same short PermissionError retry save_yaml() already uses for a
transient Windows sharing violation. save_memory() and edit_memory()
now go through it instead of the direct open().

CodeEditor._save_edited_file() is left out of this change: os.replace
makes the destination inherit the temp file's permissions rather than
the original's, and tempfile.mkstemp creates that temp file 0600, so
an executable source file would lose its +x bit on save. Memory files
are always plain text Serena itself creates, so this doesn't apply to
them.

Refs #1958

* fix(memories): preserve file mode in write_file_atomic

mkstemp() creates the temp file with mode 0600 regardless of umask, and
os.replace() carries that mode into the destination. save_memory() and
edit_memory() going through write_file_atomic() silently tightened an
existing memory file's permissions (e.g. 0644 -> 0600) on every save or
edit, dropping group/other read access.

Restore the target's existing mode before the replace, or fall back to
what a plain open(path, "w") would give a brand-new file (0666 masked
by the process umask) when there is nothing to preserve.

Refs #1958

* test(memories): skip POSIX permission-preservation tests on Windows

os.chmod does not set POSIX group/other bits on Windows, so
test_save_memory_preserves_existing_file_permissions and
test_edit_memory_preserves_existing_file_permissions assert a mode
the platform cannot produce. Matches the existing skipif convention
used elsewhere in this suite for POSIX-only filesystem behavior.

Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>

---------

Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
2026-09-03 15:04:12 +02:00
Yu-0312 69ab73dc7f fix(mcp): report Serena version in initialize 2026-09-03 14:55:31 +02:00
Johan Larsson 25631db556 feat(solidlsp): add Fatou support
Refs #1931
2026-09-03 14:43:25 +02:00
TANIGUCHI KoheiandClaude Opus 5 e771adedb5 Update the flake inputs
The inputs had been pinned for a year.

Verified on aarch64-darwin: `nix build` succeeds and the resulting `bin/serena`
reports `Serena 1.7.1.dev0`. The Linux packages and devShell evaluate cleanly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:05:51 +02:00
TANIGUCHI KoheiandClaude Opus 5 6d387aa8ec Adapt the flake to nixpkgs' deprecation of the stdenv platform predicates
nixpkgs now warns on every access to the `stdenv.is*` shorthands, which hide
the build/host/target distinction
(https://github.com/NixOS/nixpkgs/pull/518407). The nixpkgs pinned here
predates that change, but a future update will surface the warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:05:51 +02:00
TANIGUCHI KoheiandClaude Opus 5 4ec3ce398e Ignore the symlink a Nix build leaves at the repository root
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:05:51 +02:00
Amir Fathi e1322a3b99 fix(dart): wait for analyzer readiness signal before returning from start()
DartLanguageServer registered handlers for $/analyzerStatus and
experimental/serverStatus but both were no-ops, so start() returned as
soon as initialized was sent instead of waiting for either signal, unlike
every other backend (pyright, basedpyright, rust-analyzer, clojure-lsp,
jedi, omnisharp, clangd) that receives the same notifications. A request
issued right after activation could return before the workspace scan
finished.

Gate on a threading.Event set by either notification, bounded by 60s,
mirroring pyright_server.py's analysis_complete pattern.
2026-09-03 13:02:50 +02:00
Dominik Jain 813fd98f4f CLI: Fix project index-file command not using only the relevant language server to index the given file
Resolves #1965
2026-09-02 15:12:16 +02:00
Dr. Dominik Jain c8ef9d358e Merge pull request #1872 from AmirF194/fix/1871-nextflow-scan-flush-flag
fix(nextflow): don't mark workspace scan flushed when both probes fail
2026-09-02 13:46:24 +02:00
Amir Fathi 47c0a4bb66 fix(hooks): reset reminder counters after a successful Codex Serena call
Codex's documented hook wiring only routes `serena-hooks remind` through
PreToolUse on the `Bash` matcher, so `ToolUseCounter.update()`'s
reset-on-Serena-tool-use branch is never reached there: it only fires when
`remind` itself is invoked for a `mcp__serena__*` tool name, which the
Bash-only matcher excludes. Reminder counters therefore never clear after a
successful Serena call, and an unrelated grep/read burst afterwards can trip
the deny threshold on state that should have been reset.

Add a `serena-hooks reset` command, wired to PostToolUse on Serena's own
tools, that resets the counters after a successful call. Gated on the call
having succeeded (`tool_response` carrying no `isError: true`, the MCP
`tools/call` result shape) so a failed Serena call does not mask a real
grep/read streak, per the issue's own acceptance criteria. The symbolic-tool
classification is shared with the existing PreToolUse hook via a small
extracted helper so both agree on what counts as a Serena tool.

Fixes #1852
2026-09-02 13:21:42 +02:00