From 5aeb076d8ae48667e5fd7820e06f97b2c3a57bec Mon Sep 17 00:00:00 2001 From: Parker Rowe Date: Fri, 8 May 2026 15:30:02 -0400 Subject: [PATCH] feat: add CircleCI language server support Adds `circleci-yaml-language-server` as a built-in lsp. Will auto download the latest version of the LSP from the releases page: https://github.com/CircleCI-Public/circleci-yaml-language-server --- packages/opencode/src/lsp/server.ts | 78 +++++++++++++++++++++++++++ packages/web/src/content/docs/lsp.mdx | 73 ++++++++++++------------- 2 files changed, 115 insertions(+), 36 deletions(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 2be68aa5a92d..a79bb7bee14b 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -1965,6 +1965,84 @@ export const HLS: Info = { }, } +export const CircleCILS: Info = { + id: "circleci", + extensions: [".yaml", ".yml"], + root: async (file, ctx) => { + const relative = path.relative(ctx.directory, file) + if (!relative.startsWith(".circleci" + path.sep) && !relative.startsWith(".circleci/")) return undefined + return ctx.directory + }, + async spawn(root, _ctx, flags) { + const suffix = process.platform === "win32" ? ".exe" : "" + const binName = "circleci-yaml-language-server" + suffix + const managedBin = path.join(Global.Path.bin, binName) + const versionFile = managedBin + ".version" + + let bin: string | undefined = which("circleci-yaml-language-server") ?? undefined + + if (bin) { + return { process: spawn(bin, ["-stdio"], { cwd: root }) } + } + + if (flags.disableLspDownload) return + + const fetchLatestRelease = async () => { + const response = await fetch( + "https://api.github.com/repos/CircleCI-Public/circleci-yaml-language-server/releases/latest", + ) + if (!response.ok) return undefined + return (await response.json()) as { + tag_name?: string + assets?: { name?: string; browser_download_url?: string }[] + } + } + + const downloadBinary = async (release: { + tag_name?: string + assets?: { name?: string; browser_download_url?: string }[] + }) => { + const cciArch = process.arch === "arm64" ? "arm64" : "amd64" + const cciPlatform = process.platform === "win32" ? "windows" : process.platform + const assetName = `${cciPlatform}-${cciArch}-lsp${suffix}` + + const asset = (release.assets ?? []).find((a) => a.name === assetName) + if (!asset?.browser_download_url) return undefined + + const downloadResponse = await fetch(asset.browser_download_url) + if (!downloadResponse.ok || !downloadResponse.body) return undefined + + await Filesystem.writeStream(managedBin, downloadResponse.body) + + if (process.platform !== "win32") { + await fs.chmod(managedBin, 0o755).catch(() => {}) + } + + await fs.writeFile(versionFile, release.tag_name ?? "unknown").catch(() => {}) + return managedBin + } + + if (await pathExists(managedBin)) { + bin = managedBin + + const installedVersion = await fs.readFile(versionFile, "utf-8").catch(() => undefined) + fetchLatestRelease() + .then(async (release) => { + if (!release?.tag_name || release.tag_name === installedVersion) return + await downloadBinary(release) + }) + .catch(() => {}) + } else { + const release = await fetchLatestRelease() + if (!release) return + bin = await downloadBinary(release) + if (!bin) return + } + + return { process: spawn(bin, ["-stdio"], { cwd: root }) } + }, +} + export const JuliaLS: Info = { id: "julials", extensions: [".jl"], diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx index b9428e5b2d30..a87eb66ff388 100644 --- a/packages/web/src/content/docs/lsp.mdx +++ b/packages/web/src/content/docs/lsp.mdx @@ -11,42 +11,43 @@ OpenCode can integrate with Language Server Protocol (LSP) servers to use diagno OpenCode comes with several built-in LSP servers for popular languages: -| LSP Server | Extensions | Requirements | -| ------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------ | -| astro | .astro | Auto-installs for Astro projects | -| bash | .sh, .bash, .zsh, .ksh | Auto-installs bash-language-server | -| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | -| csharp | .cs, .csx | `.NET SDK` installed | -| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` command available | -| dart | .dart | `dart` command available | -| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | -| elixir-ls | .ex, .exs | `elixir` command available | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | -| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` installed | -| gleam | .gleam | `gleam` command available | -| gopls | .go | `go` command available | -| hls | .hs, .lhs | `haskell-language-server-wrapper` command available | -| jdtls | .java | `Java SDK (version 21+)` installed | -| julials | .jl | `julia` and `LanguageServer.jl` installed | -| kotlin-ls | .kt, .kts | Auto-installs for Kotlin projects | -| lua-ls | .lua | Auto-installs for Lua projects | -| nixd | .nix | `nixd` command available | -| ocaml-lsp | .ml, .mli | `ocamllsp` command available | -| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` dependency in project | -| php intelephense | .php | Auto-installs for PHP projects | -| prisma | .prisma | `prisma` command available | -| pyright | .py, .pyi | `pyright` dependency installed | -| razor | .razor, .cshtml | `.NET SDK` and VS Code C# extension installed | -| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | -| rust | .rs | `rust-analyzer` command available | -| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) | -| svelte | .svelte | Auto-installs for Svelte projects | -| terraform | .tf, .tfvars | Auto-installs from GitHub releases | -| tinymist | .typ, .typc | Auto-installs from GitHub releases | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | -| vue | .vue | Auto-installs for Vue projects | -| yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | -| zls | .zig, .zon | `zig` command available | +| LSP Server | Extensions | Requirements | +| ----------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------ | +| astro | .astro | Auto-installs for Astro projects | +| bash | .sh, .bash, .zsh, .ksh | Auto-installs bash-language-server | +| circleci-yaml-language-server | .circleci/config.yml, .circleci/config.yaml | Auto-installs circleci-yaml-language-server | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | +| csharp | .cs, .csx | `.NET SDK` installed | +| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` command available | +| dart | .dart | `dart` command available | +| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | +| elixir-ls | .ex, .exs | `elixir` command available | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | +| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` installed | +| gleam | .gleam | `gleam` command available | +| gopls | .go | `go` command available | +| hls | .hs, .lhs | `haskell-language-server-wrapper` command available | +| jdtls | .java | `Java SDK (version 21+)` installed | +| julials | .jl | `julia` and `LanguageServer.jl` installed | +| kotlin-ls | .kt, .kts | Auto-installs for Kotlin projects | +| lua-ls | .lua | Auto-installs for Lua projects | +| nixd | .nix | `nixd` command available | +| ocaml-lsp | .ml, .mli | `ocamllsp` command available | +| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` dependency in project | +| php intelephense | .php | Auto-installs for PHP projects | +| prisma | .prisma | `prisma` command available | +| pyright | .py, .pyi | `pyright` dependency installed | +| razor | .razor, .cshtml | `.NET SDK` and VS Code C# extension installed | +| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | +| rust | .rs | `rust-analyzer` command available | +| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) | +| svelte | .svelte | Auto-installs for Svelte projects | +| terraform | .tf, .tfvars | Auto-installs from GitHub releases | +| tinymist | .typ, .typc | Auto-installs from GitHub releases | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | +| vue | .vue | Auto-installs for Vue projects | +| yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | +| zls | .zig, .zon | `zig` command available | LSP is disabled by default. When enabled, servers start when one of the above file extensions is detected and the requirements are met.