M5: LSP pool and diagnostics wiring
Adds the DiagnosticsSource seam trait in harness-core::lsp (kept out of harness-tools so tools never link the LSP crate directly), and implements it in harness-lsp as a pool that lazily spawns one language server per file extension (rust-analyzer, typescript-language-server, gopls, pyright-langserver) only when the binary is on PATH. Adds harness-tools::diagnostics and wires diagnostics into edit/write/bash/glob/grep output.
This commit is contained in:
@@ -16,6 +16,7 @@ use harness_core::config::{self, Config, ConfigError};
|
||||
use harness_core::engine::jobs::{JobBoard, JobState, LaunchSpec};
|
||||
use harness_core::engine::{run_session, RunConfig, StepContext};
|
||||
use harness_core::event::{AppEvent, EventBus, RunOutcome};
|
||||
use harness_core::lsp::DiagnosticsSource;
|
||||
use harness_core::permission::{PermissionReply, PermissionService, Rule, Ruleset};
|
||||
use harness_core::store::{Store, StoreError};
|
||||
use harness_core::tool::{
|
||||
@@ -90,6 +91,9 @@ struct EngineInner {
|
||||
providers: ProviderRegistry,
|
||||
catalog: ModelCatalog,
|
||||
agents: AgentRegistry,
|
||||
/// LSP diagnostics pool (edit/write surface errors). Shared across sessions; servers spawn
|
||||
/// lazily on first touch.
|
||||
diagnostics: Option<Arc<dyn DiagnosticsSource>>,
|
||||
cwd: PathBuf,
|
||||
data_dir: PathBuf,
|
||||
runs: Mutex<HashMap<SessionId, RunHandle>>,
|
||||
@@ -196,6 +200,20 @@ impl EngineHandle {
|
||||
// `init` warms the cache in the background for the next launch.
|
||||
let catalog = ModelCatalog::load_cached_or_baked(&ModelCatalog::default_cache_path());
|
||||
|
||||
// LSP pool: built-ins present on PATH, plus any config-declared servers.
|
||||
let lsp_servers: Vec<harness_lsp::ServerConfig> = config
|
||||
.lsp
|
||||
.iter()
|
||||
.map(|(name, c)| harness_lsp::ServerConfig {
|
||||
name: name.clone(),
|
||||
command: c.command.clone(),
|
||||
args: c.args.clone(),
|
||||
extensions: c.extensions.clone(),
|
||||
})
|
||||
.collect();
|
||||
let diagnostics: Option<Arc<dyn DiagnosticsSource>> =
|
||||
Some(Arc::new(harness_lsp::LspPool::new(cwd.clone(), lsp_servers)));
|
||||
|
||||
let inner = Arc::new(EngineInner {
|
||||
config,
|
||||
store,
|
||||
@@ -205,6 +223,7 @@ impl EngineHandle {
|
||||
providers,
|
||||
catalog,
|
||||
agents,
|
||||
diagnostics,
|
||||
cwd,
|
||||
data_dir,
|
||||
runs: Mutex::new(HashMap::new()),
|
||||
@@ -328,6 +347,7 @@ impl EngineHandle {
|
||||
spawner: Some(self.inner.clone()),
|
||||
job_board: Some(board),
|
||||
context_reporter: None, // root session has no parent board to report to
|
||||
diagnostics: self.inner.diagnostics.clone(),
|
||||
};
|
||||
let run_config = RunConfig {
|
||||
agent_name: agent.name.clone(),
|
||||
@@ -633,6 +653,7 @@ impl EngineInner {
|
||||
spawner: Some(self.arc()),
|
||||
job_board: Some(board),
|
||||
context_reporter: reporter,
|
||||
diagnostics: self.diagnostics.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user