Crate renames: - zesdex-entities::seaorm → domain (misleading name, no SeaORM used) - zesdex-dto → merged into zesdex-entities (100% re-exports) - zesdex-libs → zesdex-infra (vague name) Module renames: - app/harness → guard (misleading: safety gatekeeper, not test harness) - runtime/commands → action_dispatch (name clashed with controller/command) - resources → prompts (embedded prompt text, not general resources) - tool/seqthink → sequential_think (unreadable abbreviation) - msglog/query → insert (module only inserts, never queries) Dead code removal: - app/mode/help.rs (orphaned — not declared in mod.rs) - app/mode/loading.rs (orphaned — not declared in mod.rs) File splitting (71 new files, avg ~115 lines/file): - app/runtime/actions/: 1→8 files (was 2030 lines) - view/overlays/: 1→16 files (was 1167 lines) - tool/lsp/: 1→8 per-tool files (was 909 lines) - main.rs: 1→5 files (session, daemon, attach, event_loop) - workflow/engine + hive_mind: 2→10 files - subagent/engine + auto: 2→9 files - lsp/provisioner: 1→5 files - review/: 1→6 files - guard/: 1→2 files (extracted patterns) - state/misc: 1→3 files (input, scroll) - mcp/: 1→3 files (transport, adapter) - stream/json_repair extracted from turn.rs DRY: - Pattern constants (STUB_PATTERNS etc) in guard/patterns shared with subagent - 3 near-identical background spawners → 1 generic + thin wrappers - Shared spawn_subagent_with_drain() extracted - Shared create_session() in main - write_osc52 deduplicated Bug fixes: - archive_message(): sess.db → db (wrong variable name) - execute_one_tool(): wrong parameter name - check_credential_read() function was missing (restored from test expectations)
227 lines
8.9 KiB
Rust
227 lines
8.9 KiB
Rust
//! Static language server definitions and core types.
|
|
//!
|
|
//! Defines the set of supported LSP servers, their install tiers, and the
|
|
//! result/enum types used across the provisioner.
|
|
|
|
/// Optional progress callback type (non-owning, caller ensures liveness
|
|
/// for the duration of the provisioning call).
|
|
/// Intended to be hooked up to a UI toast / status-bar mechanism.
|
|
pub type ProgressFn<'a> = Option<&'a dyn Fn(&str)>;
|
|
|
|
/// Result of attempting to make a single language server available.
|
|
///
|
|
/// The caller should switch on this variant: `AlreadyAvailable` and
|
|
/// Installed both mean the binary can be launched; Failed means we
|
|
/// gave up and the user needs to install manually (see `manual_instructions`).
|
|
#[derive(Debug, Clone)]
|
|
pub enum ProvisionResult {
|
|
/// Binary was already on PATH — no install was needed.
|
|
AlreadyAvailable {
|
|
server_name: String,
|
|
language: String,
|
|
binary_path: String,
|
|
},
|
|
/// Provisioner successfully installed the binary during this run.
|
|
Installed {
|
|
server_name: String,
|
|
language: String,
|
|
binary_path: String,
|
|
},
|
|
/// Every install tier failed. Tells the user how to install by hand.
|
|
Failed {
|
|
language: String,
|
|
server_name: String,
|
|
reason: String,
|
|
},
|
|
}
|
|
|
|
/// Sentinel command names used by `provision_single` to detect "download"
|
|
/// tiers (which are dispatched to `download_*` helpers rather than
|
|
/// `run_command`). Kept as constants so `supported_servers` stays readable.
|
|
pub(super) const DOWNLOAD_RUST_BIN: &str = "__download_rust_analyzer__";
|
|
pub(super) const DOWNLOAD_JDTLS: &str = "__download_jdtls__";
|
|
|
|
/// Static description of a single language server: how to detect it,
|
|
/// what file extensions it handles, and how to install it.
|
|
#[derive(Debug, Clone)]
|
|
pub struct LanguageServerDef {
|
|
/// Human-readable server name (e.g. "rust-analyzer").
|
|
pub name: String,
|
|
/// LSP language identifier (e.g. "rust").
|
|
pub language: String,
|
|
/// File extensions this server handles (with leading dot).
|
|
pub extensions: Vec<String>,
|
|
/// Candidate binary names — the provisioner accepts whichever appears on PATH.
|
|
pub binary_names: Vec<String>,
|
|
/// Install strategies, tried in order until one succeeds.
|
|
pub install_tiers: Vec<InstallTier>,
|
|
}
|
|
|
|
/// A single install attempt: a command (plus args) gated by a prerequisite.
|
|
///
|
|
/// `requires` lists binaries that must already be on PATH for this tier
|
|
/// to be considered. If any required binary is missing, the tier is
|
|
/// skipped (not attempted) so we don't produce misleading failures
|
|
/// like "rustup: command not found" when the real fix was to install
|
|
/// rustup first.
|
|
#[derive(Debug, Clone)]
|
|
pub struct InstallTier {
|
|
/// Short human-readable label, e.g. "rustup component".
|
|
pub label: String,
|
|
/// Binaries that must be available before this tier is attempted.
|
|
pub requires: Vec<String>,
|
|
/// Command to run.
|
|
pub command: String,
|
|
/// Arguments to pass to the command.
|
|
pub args: Vec<String>,
|
|
}
|
|
|
|
/// Return the static set of supported language servers.
|
|
///
|
|
/// The order is significant: it determines provisioning order and
|
|
/// the order results appear in `provision_all_with_progress()`. Tier 1 paths are
|
|
/// the canonical/idiomatic install for each ecosystem; later tiers
|
|
/// are fallbacks for hosts that lack the primary tooling.
|
|
///
|
|
/// Why hard-coded rather than loaded from settings: the set is small,
|
|
/// changes rarely, and bundling it lets the provisioner run before any
|
|
/// user config has been read (e.g. on first launch).
|
|
pub fn supported_servers() -> Vec<LanguageServerDef> {
|
|
vec![
|
|
LanguageServerDef {
|
|
name: "rust-analyzer".to_string(),
|
|
language: "rust".to_string(),
|
|
extensions: vec![".rs".to_string()],
|
|
binary_names: vec!["rust-analyzer".to_string()],
|
|
install_tiers: vec![
|
|
InstallTier {
|
|
label: "rustup component".to_string(),
|
|
requires: vec!["rustup".to_string()],
|
|
command: "rustup".to_string(),
|
|
args: vec![
|
|
"component".to_string(),
|
|
"add".to_string(),
|
|
"rust-analyzer".to_string(),
|
|
],
|
|
},
|
|
InstallTier {
|
|
label: "pacman".to_string(),
|
|
requires: vec!["pacman".to_string()],
|
|
command: "pacman".to_string(),
|
|
args: vec![
|
|
"-S".to_string(),
|
|
"--noconfirm".to_string(),
|
|
"--needed".to_string(),
|
|
"rust-analyzer".to_string(),
|
|
],
|
|
},
|
|
InstallTier {
|
|
label: "brew".to_string(),
|
|
requires: vec!["brew".to_string()],
|
|
command: "brew".to_string(),
|
|
args: vec!["install".to_string(), "rust-analyzer".to_string()],
|
|
},
|
|
InstallTier {
|
|
label: "cargo install".to_string(),
|
|
requires: vec!["cargo".to_string()],
|
|
command: "cargo".to_string(),
|
|
args: vec![
|
|
"install".to_string(),
|
|
"--locked".to_string(),
|
|
"rust-analyzer".to_string(),
|
|
],
|
|
},
|
|
InstallTier {
|
|
label: "download prebuilt".to_string(),
|
|
requires: vec!["curl".to_string(), "tar".to_string()],
|
|
command: DOWNLOAD_RUST_BIN.to_string(),
|
|
args: vec![],
|
|
},
|
|
],
|
|
},
|
|
LanguageServerDef {
|
|
name: "typescript-language-server".to_string(),
|
|
language: "typescript".to_string(),
|
|
extensions: vec![
|
|
".ts".to_string(),
|
|
".tsx".to_string(),
|
|
".js".to_string(),
|
|
".jsx".to_string(),
|
|
],
|
|
binary_names: vec!["typescript-language-server".to_string()],
|
|
install_tiers: vec![InstallTier {
|
|
label: "npm global".to_string(),
|
|
requires: vec!["npm".to_string()],
|
|
command: "npm".to_string(),
|
|
args: vec![
|
|
"install".to_string(),
|
|
"-g".to_string(),
|
|
"typescript".to_string(),
|
|
"typescript-language-server".to_string(),
|
|
],
|
|
}],
|
|
},
|
|
LanguageServerDef {
|
|
name: "gopls".to_string(),
|
|
language: "go".to_string(),
|
|
extensions: vec![".go".to_string()],
|
|
binary_names: vec!["gopls".to_string()],
|
|
install_tiers: vec![InstallTier {
|
|
label: "go install".to_string(),
|
|
requires: vec!["go".to_string()],
|
|
command: "go".to_string(),
|
|
args: vec![
|
|
"install".to_string(),
|
|
"golang.org/x/tools/gopls@latest".to_string(),
|
|
],
|
|
}],
|
|
},
|
|
LanguageServerDef {
|
|
name: "jdtls".to_string(),
|
|
language: "java".to_string(),
|
|
extensions: vec![".java".to_string()],
|
|
binary_names: vec![
|
|
"jdtls".to_string(),
|
|
"eclipse-jdt-ls".to_string(),
|
|
"jdtls-launcher".to_string(),
|
|
],
|
|
install_tiers: vec![
|
|
InstallTier {
|
|
label: "pacman".to_string(),
|
|
requires: vec!["java".to_string(), "pacman".to_string()],
|
|
command: "pacman".to_string(),
|
|
args: vec![
|
|
"-S".to_string(),
|
|
"--noconfirm".to_string(),
|
|
"--needed".to_string(),
|
|
"eclipse-jdt-ls".to_string(),
|
|
],
|
|
},
|
|
InstallTier {
|
|
label: "apt".to_string(),
|
|
requires: vec!["java".to_string(), "apt".to_string()],
|
|
command: "sudo".to_string(),
|
|
args: vec![
|
|
"apt".to_string(),
|
|
"install".to_string(),
|
|
"-y".to_string(),
|
|
"eclipse-jdt-ls".to_string(),
|
|
],
|
|
},
|
|
InstallTier {
|
|
label: "brew".to_string(),
|
|
requires: vec!["java".to_string(), "brew".to_string()],
|
|
command: "brew".to_string(),
|
|
args: vec!["install".to_string(), "jdtls".to_string()],
|
|
},
|
|
InstallTier {
|
|
label: "download from eclipse".to_string(),
|
|
requires: vec!["java".to_string(), "curl".to_string(), "tar".to_string()],
|
|
command: DOWNLOAD_JDTLS.to_string(),
|
|
args: vec![],
|
|
},
|
|
],
|
|
},
|
|
]
|
|
}
|