Skip to content

LSP Phase 7: CLI + config plumbing through build_channels - #31

Merged
yogthos merged 1 commit into
mainfrom
feature/lsp-phase-7-plumbing
May 20, 2026
Merged

LSP Phase 7: CLI + config plumbing through build_channels#31
yogthos merged 1 commit into
mainfrom
feature/lsp-phase-7-plumbing

Conversation

@yogthos

@yogthos yogthos commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Phase 7 of 9. Stacked on #30 (Phase 6). The plumbing pass that connects everything end-to-end — by the end of this PR the agent actually gets LSP-aware tools attached to it.

Config schema (`src/config/mod.rs`)

```json
{
"lsp": true // built-ins on
"lsp": false // off entirely
"lsp": { // built-ins on, with per-server overrides
"rust": { "command": ["my-rust-analyzer", "--my-arg"], "env": {"RUST_LOG": "info"} },
"typescript": { "disabled": true }
}
}
```

`LspServerConfig`: `command`, `extensions`, `env`, `initialization`, `disabled` — all optional, missing fields fall back to the built-in defaults.

4 config-parse tests: bool form, per-server map form, absent-is-None (default-on), mixed command/disabled entries.

CLI (`src/cli.rs`)

  • `--no-lsp` flag: disables LSP entirely.
  • `resolve_lsp_enabled(cli, cfg)` resolver: `no-tools` or `no-lsp` turns it off; otherwise config (default `true`) decides.

Default server commands (`src/lsp/spawn.rs::default_commands`)

Server id Program Args
rust rust-analyzer
typescript typescript-language-server --stdio
pyright pyright-langserver --stdio
clojure-lsp clojure-lsp

Plumbing

`main::build_channels` grows a 10th return slot: `Option<Arc>`. `compile_lsp_commands` merges defaults + user overrides into the spawner command map.

Threaded through:

  • `provider::build_agent` + `builder::build_agent_inner` — both get a new `lsp_manager` arg.
  • `builder.rs` passes the manager to `WriteTool` / `EditTool` / `ReadTool` (Phase 6 prepared these fields) AND registers `LspTool` when the manager is present (Phase 5's tool now actually attaches).
  • `run_interactive` accepts and forwards the manager.
  • Plan-switch rebuild passes the live `lsp_manager.clone()` so the rebuilt agent still has LSP tools — same pattern as the bg-store fix.
  • 7 slash.rs sub-rebuilds + 2 ui/mod.rs prompt-switch sites pass `None` (intentional — `/model`, `/context-reset` etc. don't need LSP).
  • ACP path passes `None` (acp doesn't need LSP for v1).

What this PR doesn't do

  • Feature gate: Phase 8 adds `feature = "lsp"` to make the entire module opt-out at compile time. Until then it's always compiled in.
  • Docs + manual rust-analyzer test plan: Phase 9.

Test plan

  • `cargo build` clean
  • `cargo test --bin dirge -- --skip plugin` → 426 passing (was 422; +4 config tests from Phase 7)
  • `cargo fmt --check` clean

Next: Phase 8 (feature flag) and Phase 9 (docs + manual end-to-end against real rust-analyzer).

@yogthos
yogthos changed the base branch from feature/lsp-phase-6-edit-integration to main May 20, 2026 01:46
src/config/mod.rs
- LspConfig: untagged enum, accepts `true`/`false` OR a map of
  per-server overrides.
- LspServerConfig: all-optional fields (command, extensions, env,
  initialization, disabled). Missing fields fall back to built-in.
- Config gains an optional `lsp` field; default-None (which the CLI
  resolver treats as enabled-with-built-ins).
- 4 config-parse tests: bool form, per-server map form, absent-is-None,
  mixed command/disabled entries.

src/cli.rs
- `--no-lsp` flag.
- `resolve_lsp_enabled(cli, cfg)` resolver: no-tools or no-lsp turns it
  off; otherwise the config bool (default true) decides.

src/lsp/spawn.rs
- ProcessSpawner::default_commands(): the 4 built-in commands for v1
  servers (rust-analyzer, typescript-language-server --stdio,
  pyright-langserver --stdio, clojure-lsp). User config overrides are
  merged in main::compile_lsp_commands.

src/main.rs
- build_channels grows a 10th return slot: Option<Arc<LspManager>>.
  Constructed when lsp_enabled, via ProcessSpawner with merged defaults
  + user overrides.
- compile_lsp_commands: starts from defaults, applies per-server
  overrides (disabled removes, command replaces, env/init merge).
- Threaded through all 3 `build_agent` call sites + run_interactive.

src/provider.rs + src/agent/builder.rs
- New `lsp_manager: Option<Arc<LspManager>>` arg on build_agent /
  build_agent_inner. Threaded down to the WriteTool / EditTool /
  ReadTool constructors (which Phase 6 prepared the field for) AND to
  the LspTool registration (Phase 5's tool now actually gets attached
  to the agent when lsp_manager is present).

src/ui/mod.rs + src/ui/slash.rs + src/extras/acp/mod.rs
- run_interactive accepts and forwards lsp_manager.
- Plan-switch rebuild passes the live lsp_manager.clone() (so the
  rebuilt agent still has LSP tools — same pattern as the bg-store
  fix from Phase 5).
- 7 slash.rs sub-rebuild sites + 2 ui/mod.rs prompt-switch sites pass
  `None` for lsp_manager (intentional — these rebuild for /model,
  /context-reset etc., which don't need to re-attach LSP).
- ACP path passes `None`.

src/agent/tools/lsp.rs
- Drops the Phase-5 `#![allow(dead_code)]` now that builder.rs wires it.

Phase 6: 116, Phase 7: +4 config tests -> 120 LSP tests.
Suite: 422 -> 426.
@yogthos
yogthos force-pushed the feature/lsp-phase-7-plumbing branch from bba4943 to 9f746ab Compare May 20, 2026 01:54
@yogthos
yogthos merged commit 68aef91 into main May 20, 2026
1 check passed
@yogthos
yogthos deleted the feature/lsp-phase-7-plumbing branch May 20, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant