From 9313c0eeb00929d29caaef945dd24b2caa595d7c Mon Sep 17 00:00:00 2001 From: Guilherme Beira Date: Mon, 15 Jun 2026 10:07:29 -0300 Subject: [PATCH] refactor(lsp): rename worker iii-lsp -> lsp; vscode ext falls back to old binary --- .github/workflows/create-tag.yml | 2 +- .github/workflows/release.yml | 2 +- README.md | 4 +-- iii-lsp-vscode/extension.js | 30 +++++++++++++++- {iii-lsp => lsp}/Cargo.lock | 38 ++++++++++---------- {iii-lsp => lsp}/Cargo.toml | 6 ++-- {iii-lsp => lsp}/README.md | 8 ++--- {iii-lsp => lsp}/iii.worker.yaml | 6 ++-- {iii-lsp => lsp}/openvsx-verification.txt | 0 {iii-lsp => lsp}/src/analyzer.rs | 0 {iii-lsp => lsp}/src/completions.rs | 0 {iii-lsp => lsp}/src/diagnostics.rs | 18 +++++----- {iii-lsp => lsp}/src/engine_client.rs | 2 +- {iii-lsp => lsp}/src/engine_introspection.rs | 0 {iii-lsp => lsp}/src/hover.rs | 0 {iii-lsp => lsp}/src/lib.rs | 2 +- {iii-lsp => lsp}/src/main.rs | 10 +++--- {iii-lsp => lsp}/tests/introspection.rs | 2 +- 18 files changed, 79 insertions(+), 51 deletions(-) rename {iii-lsp => lsp}/Cargo.lock (99%) rename {iii-lsp => lsp}/Cargo.toml (92%) rename {iii-lsp => lsp}/README.md (90%) rename {iii-lsp => lsp}/iii.worker.yaml (78%) rename {iii-lsp => lsp}/openvsx-verification.txt (100%) rename {iii-lsp => lsp}/src/analyzer.rs (100%) rename {iii-lsp => lsp}/src/completions.rs (100%) rename {iii-lsp => lsp}/src/diagnostics.rs (98%) rename {iii-lsp => lsp}/src/engine_client.rs (99%) rename {iii-lsp => lsp}/src/engine_introspection.rs (100%) rename {iii-lsp => lsp}/src/hover.rs (100%) rename {iii-lsp => lsp}/src/lib.rs (91%) rename {iii-lsp => lsp}/src/main.rs (94%) rename {iii-lsp => lsp}/tests/introspection.rs (96%) diff --git a/.github/workflows/create-tag.yml b/.github/workflows/create-tag.yml index dd79691d..6bb5f768 100644 --- a/.github/workflows/create-tag.yml +++ b/.github/workflows/create-tag.yml @@ -15,7 +15,7 @@ on: - email - harness - iii-directory - - iii-lsp + - lsp - iii-lsp-vscode - image-resize - mcp diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69daddcb..eb2bcbf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ on: - 'email/v*' - 'harness/v*' - 'iii-directory/v*' - - 'iii-lsp/v*' + - 'lsp/v*' - 'image-resize/v*' - 'mcp/v*' - 'shell/v*' diff --git a/README.md b/README.md index 0a2bd858..d8d3a611 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ npx skills add iii-hq/iii --all | [`harness`](harness/) | Node | TS port of the iii harness stack — bundles `harness` (provider registry + credentials/settings/permissions via the `configuration` worker), `turn-orchestrator`, `approval-gate`, `session`, `hook-fanout`, `models-catalog`, the `provider-*` workers, `llm-budget`, and `context-compaction` as one pnpm monorepo. See [`harness/README.md`](harness/README.md). | | [`database`](database/) | Rust | PostgreSQL, MySQL, and SQLite client — query, execute, transactions, prepared statements, and change feeds. | | [`iii-directory`](iii-directory/) | Rust | Engine introspection (functions / triggers / workers), workers-registry proxy, and filesystem-backed skill + prompt reader. | -| [`iii-lsp`](iii-lsp/) | Rust | Language Server for iii function ids, trigger configs, and worker discovery. Autocomplete / hover across JS/TS, Python, Rust. | -| [`iii-lsp-vscode`](iii-lsp-vscode/) | Node | VS Code extension that embeds `iii-lsp`. | +| [`lsp`](lsp/) | Rust | Language Server for iii function ids, trigger configs, and worker discovery. Autocomplete / hover across JS/TS, Python, Rust. | +| [`iii-lsp-vscode`](iii-lsp-vscode/) | Node | VS Code extension that embeds the `lsp` server. | | [`image-resize`](image-resize/) | Rust | Image resize via channel I/O — JPEG/PNG/WebP with EXIF auto-orient, scale-to-fit / crop-to-fit. | | [`llm-budget`](llm-budget/) | Rust | Workspace + agent LLM spend caps with alerts, forecast, and period rollover under `budget::*`. | | [`mcp`](mcp/) | Rust | MCP 2025-06-18 Streamable HTTP bridge — exposes iii functions tagged `mcp.expose` as MCP tools. | diff --git a/iii-lsp-vscode/extension.js b/iii-lsp-vscode/extension.js index 9f0af83d..c25e92d8 100644 --- a/iii-lsp-vscode/extension.js +++ b/iii-lsp-vscode/extension.js @@ -1,10 +1,38 @@ const vscode = require("vscode"); +const fs = require("node:fs"); +const path = require("node:path"); const { LanguageClient, TransportKind } = require("vscode-languageclient/node"); const { ensureServerBinary } = require("./installer"); let client; +// Resolve the server binary on PATH, preferring the new `lsp` name and +// falling back to the legacy `iii-lsp` name for older installs. +function resolvePathBinary() { + const candidates = ["lsp", "iii-lsp"]; + const pathEntries = (process.env.PATH || "").split(path.delimiter).filter(Boolean); + const exts = process.platform === "win32" + ? (process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";") + : [""]; + for (const candidate of candidates) { + for (const dir of pathEntries) { + for (const ext of exts) { + const full = path.join(dir, candidate + ext); + try { + if (fs.statSync(full).isFile()) { + return full; + } + } catch { + // not here, keep looking + } + } + } + } + // Nothing on PATH; default to the new name and let the OS resolve it. + return candidates[0]; +} + async function activate(context) { const config = vscode.workspace.getConfiguration("iii-lsp"); const engineUrl = config.get("engineUrl") || "ws://127.0.0.1:49134"; @@ -17,7 +45,7 @@ async function activate(context) { vscode.window.showWarningMessage( `Failed to install iii-lsp binary. Falling back to configured path or PATH lookup. ${message}` ); - serverPath = config.get("serverPath") || "iii-lsp"; + serverPath = config.get("serverPath") || resolvePathBinary(); } const serverOptions = { diff --git a/iii-lsp/Cargo.lock b/lsp/Cargo.lock similarity index 99% rename from iii-lsp/Cargo.lock rename to lsp/Cargo.lock index d20f4e7e..8b0c06a9 100644 --- a/iii-lsp/Cargo.lock +++ b/lsp/Cargo.lock @@ -710,25 +710,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "iii-lsp" -version = "0.1.2" -dependencies = [ - "clap", - "dashmap", - "iii-sdk", - "serde", - "serde_json", - "tokio", - "tower-lsp-server", - "tracing", - "tracing-subscriber", - "tree-sitter", - "tree-sitter-python", - "tree-sitter-rust", - "tree-sitter-typescript", -] - [[package]] name = "iii-observability" version = "0.19.2" @@ -879,6 +860,25 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lsp" +version = "0.1.2" +dependencies = [ + "clap", + "dashmap", + "iii-sdk", + "serde", + "serde_json", + "tokio", + "tower-lsp-server", + "tracing", + "tracing-subscriber", + "tree-sitter", + "tree-sitter-python", + "tree-sitter-rust", + "tree-sitter-typescript", +] + [[package]] name = "matchers" version = "0.2.0" diff --git a/iii-lsp/Cargo.toml b/lsp/Cargo.toml similarity index 92% rename from iii-lsp/Cargo.toml rename to lsp/Cargo.toml index 2f3a35b4..6416d2a5 100644 --- a/iii-lsp/Cargo.toml +++ b/lsp/Cargo.toml @@ -1,15 +1,15 @@ [package] -name = "iii-lsp" +name = "lsp" version = "0.1.2" edition = "2021" publish = false [lib] -name = "iii_lsp" +name = "lsp" path = "src/lib.rs" [[bin]] -name = "iii-lsp" +name = "lsp" path = "src/main.rs" [dependencies] diff --git a/iii-lsp/README.md b/lsp/README.md similarity index 90% rename from iii-lsp/README.md rename to lsp/README.md index e421fbef..60a9df72 100644 --- a/iii-lsp/README.md +++ b/lsp/README.md @@ -1,4 +1,4 @@ -# iii-lsp +# lsp Language Server Protocol implementation for the [iii engine](https://github.com/iii-hq/iii). Provides autocompletion, hover documentation, and diagnostics for iii function calls and trigger registrations directly inside any LSP-capable editor. @@ -26,7 +26,7 @@ When the engine is not reachable on startup, the server stays up and returns emp ```bash cargo build --release -./target/release/iii-lsp --url ws://127.0.0.1:49134 +./target/release/lsp --url ws://127.0.0.1:49134 ``` The binary speaks LSP over stdio; spawn it from your editor's LSP client. @@ -51,7 +51,7 @@ Use the bundled VS Code extension, which downloads the matching `iii-lsp` binary ```lua vim.lsp.config.iii = { - cmd = { '/path/to/iii-lsp', '--url', 'ws://127.0.0.1:49134' }, + cmd = { '/path/to/lsp', '--url', 'ws://127.0.0.1:49134' }, filetypes = { 'typescript', 'typescriptreact', 'javascript', 'python', 'rust' }, } vim.lsp.enable('iii') @@ -59,7 +59,7 @@ vim.lsp.enable('iii') ### Any LSP client -Configure the client to launch the `iii-lsp` binary over stdio for the supported filetypes above. No initialization options are required. +Configure the client to launch the `lsp` binary over stdio for the supported filetypes above. No initialization options are required. ## See also diff --git a/iii-lsp/iii.worker.yaml b/lsp/iii.worker.yaml similarity index 78% rename from iii-lsp/iii.worker.yaml rename to lsp/iii.worker.yaml index fa5a3731..5b471aff 100644 --- a/iii-lsp/iii.worker.yaml +++ b/lsp/iii.worker.yaml @@ -1,11 +1,11 @@ iii: v1 -name: iii-lsp +name: lsp language: rust deploy: binary manifest: Cargo.toml -bin: iii-lsp +bin: lsp description: III Language Server — autocompletion and hover for III engine functions and triggers -# Opt out of the interface boot smoke. iii-lsp is a stdio language server: +# Opt out of the interface boot smoke. lsp is a stdio language server: # it exits on stdin EOF (so it cannot stay alive while backgrounded) and it # only consumes engine discovery — it registers no functions or trigger # types, so there is no interface to collect. diff --git a/iii-lsp/openvsx-verification.txt b/lsp/openvsx-verification.txt similarity index 100% rename from iii-lsp/openvsx-verification.txt rename to lsp/openvsx-verification.txt diff --git a/iii-lsp/src/analyzer.rs b/lsp/src/analyzer.rs similarity index 100% rename from iii-lsp/src/analyzer.rs rename to lsp/src/analyzer.rs diff --git a/iii-lsp/src/completions.rs b/lsp/src/completions.rs similarity index 100% rename from iii-lsp/src/completions.rs rename to lsp/src/completions.rs diff --git a/iii-lsp/src/diagnostics.rs b/lsp/src/diagnostics.rs similarity index 98% rename from iii-lsp/src/diagnostics.rs rename to lsp/src/diagnostics.rs index b051ebc4..7d30cc76 100644 --- a/iii-lsp/src/diagnostics.rs +++ b/lsp/src/diagnostics.rs @@ -514,7 +514,7 @@ fn check_trigger_call( diagnostics.push(Diagnostic { range: call.function_id_range, severity: Some(DiagnosticSeverity::HINT), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Function ID '{}' should use namespace format 'namespace::name'", call.function_id @@ -530,7 +530,7 @@ fn check_trigger_call( diagnostics.push(Diagnostic { range: call.function_id_range, severity: Some(DiagnosticSeverity::WARNING), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!("Unknown function '{}'", call.function_id), ..Default::default() }); @@ -555,7 +555,7 @@ fn check_trigger_call( diagnostics.push(Diagnostic { range: call.payload_range, severity: Some(DiagnosticSeverity::ERROR), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Missing required property '{}' for '{}'", name, call.function_id @@ -579,7 +579,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.function_id_range, severity: Some(DiagnosticSeverity::HINT), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Function ID '{}' should use namespace format 'namespace::name'", call.function_id @@ -592,7 +592,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.function_id_range, severity: Some(DiagnosticSeverity::WARNING), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!("Unknown function '{}'", call.function_id), ..Default::default() }); @@ -602,7 +602,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.trigger_type_range, severity: Some(DiagnosticSeverity::WARNING), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!("Unknown trigger type '{}'", call.trigger_type), ..Default::default() }); @@ -622,7 +622,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.config_range, severity: Some(DiagnosticSeverity::ERROR), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Missing required config property '{}' for trigger type '{}'", name, call.trigger_type @@ -642,7 +642,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.config_range, severity: Some(DiagnosticSeverity::WARNING), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Invalid HTTP method '{}'. Expected one of: {}", value, @@ -663,7 +663,7 @@ fn check_register_trigger_call( diagnostics.push(Diagnostic { range: call.config_range, severity: Some(DiagnosticSeverity::ERROR), - source: Some("iii-lsp".to_string()), + source: Some("lsp".to_string()), message: format!( "Cron expression must have 6 fields (sec min hour day month weekday), got {}", fields.len() diff --git a/iii-lsp/src/engine_client.rs b/lsp/src/engine_client.rs similarity index 99% rename from iii-lsp/src/engine_client.rs rename to lsp/src/engine_client.rs index 29bb49f5..a0743ea7 100644 --- a/iii-lsp/src/engine_client.rs +++ b/lsp/src/engine_client.rs @@ -25,7 +25,7 @@ impl EngineClient { metadata: Some(WorkerMetadata { runtime: "rust".to_string(), version: env!("CARGO_PKG_VERSION").to_string(), - name: "iii-lsp".to_string(), + name: "lsp".to_string(), os: std::env::consts::OS.to_string(), pid: Some(std::process::id()), telemetry: None, diff --git a/iii-lsp/src/engine_introspection.rs b/lsp/src/engine_introspection.rs similarity index 100% rename from iii-lsp/src/engine_introspection.rs rename to lsp/src/engine_introspection.rs diff --git a/iii-lsp/src/hover.rs b/lsp/src/hover.rs similarity index 100% rename from iii-lsp/src/hover.rs rename to lsp/src/hover.rs diff --git a/iii-lsp/src/lib.rs b/lsp/src/lib.rs similarity index 91% rename from iii-lsp/src/lib.rs rename to lsp/src/lib.rs index 02242982..29f1883e 100644 --- a/iii-lsp/src/lib.rs +++ b/lsp/src/lib.rs @@ -1,4 +1,4 @@ -//! Library surface for `iii-lsp`. +//! Library surface for `lsp`. //! //! The binary (`src/main.rs`) keeps its own `mod` declarations; this lib //! target re-exports the same modules so integration tests under `tests/` diff --git a/iii-lsp/src/main.rs b/lsp/src/main.rs similarity index 94% rename from iii-lsp/src/main.rs rename to lsp/src/main.rs index dab053b0..35d25f86 100644 --- a/iii-lsp/src/main.rs +++ b/lsp/src/main.rs @@ -13,7 +13,7 @@ mod engine_introspection; mod hover; #[derive(ClapParser, Debug)] -#[command(name = "iii-lsp", about = "Language Server for the III engine")] +#[command(name = "lsp", about = "Language Server for the III engine")] struct Cli { /// WebSocket URL of the III engine #[arg(long, env = "III_URL", default_value = "ws://127.0.0.1:49134")] @@ -81,7 +81,7 @@ impl LanguageServer for Backend { ..Default::default() }, server_info: Some(ServerInfo { - name: "iii-lsp".to_string(), + name: "lsp".to_string(), version: Some(env!("CARGO_PKG_VERSION").to_string()), }), ..Default::default() @@ -96,7 +96,7 @@ impl LanguageServer for Backend { .log_message( MessageType::INFO, format!( - "iii-lsp: connected to engine ({} functions, {} trigger types)", + "lsp: connected to engine ({} functions, {} trigger types)", self.engine.functions.len(), self.engine.trigger_types.len() ), @@ -106,7 +106,7 @@ impl LanguageServer for Backend { self.client .log_message( MessageType::WARNING, - "iii-lsp: engine not running, completions will be empty until engine starts", + "lsp: engine not running, completions will be empty until engine starts", ) .await; } @@ -199,7 +199,7 @@ async fn main() { .init(); let cli = Cli::parse(); - tracing::info!("starting iii-lsp, connecting to {}", cli.url); + tracing::info!("starting lsp, connecting to {}", cli.url); let engine = engine_client::EngineClient::new(&cli.url); diff --git a/iii-lsp/tests/introspection.rs b/lsp/tests/introspection.rs similarity index 96% rename from iii-lsp/tests/introspection.rs rename to lsp/tests/introspection.rs index 2bfaa1aa..50f489a3 100644 --- a/iii-lsp/tests/introspection.rs +++ b/lsp/tests/introspection.rs @@ -5,7 +5,7 @@ //! so a future engine/SDK bump that drifts the payload fails here instead //! of silently leaving the LSP caches empty. -use iii_lsp::engine_introspection::{TriggerInfo, TriggerTypeInfo}; +use lsp::engine_introspection::{TriggerInfo, TriggerTypeInfo}; use serde_json::json; /// `engine::triggers::list` returns trigger TYPES: