fix(opencode): resolve LSP for nested TypeScript sub-projects - #47181
Open
joao-jlcm wants to merge 1 commit into
Open
fix(opencode): resolve LSP for nested TypeScript sub-projects#47181joao-jlcm wants to merge 1 commit into
joao-jlcm wants to merge 1 commit into
Conversation
The `lsp` tool returned empty results or "No LSP server available for this file type." for `.ts` files in nested TypeScript sub-projects (each with its own `tsconfig.json`). Three compounding defects in the LSP runtime caused both symptoms: 1. `Typescript.root` only walked up looking for lockfiles, never for `tsconfig.json`. In a monorepo without a root lockfile, all `.ts` files resolved to the opencode working directory and shared one tsserver client that never learned about the sub-project's `tsconfig.json`. 2. `tsserver.js` was resolved from `ctx.directory` via `createRequire(path.join(dir, "package.json"))`. When the opencode working directory had no `package.json`, the call returned `undefined` and the server was marked broken, producing the explicit "No LSP server available for this file type." error. 3. The `window/workDoneProgress/create` handler returned `null` (silently dropping progress tokens) and there was no `$/progress` listener. typescript-language-server maps tsserver's `projectLoadingStart` / `projectLoadingFinish` events to standard `$/progress` notifications, so the first request raced tsserver's project load and got `[]`. Fix: - `packages/opencode/src/lsp/server.ts`: include `"tsconfig.json"` in `Typescript.root`'s include patterns (nearest wins, fully backward compatible) and resolve `tsserver.js` from the sub-project root first with a fallback to `ctx.directory`. - `packages/opencode/src/lsp/client.ts`: return the token from `window/workDoneProgress/create`, listen for `$/progress`, expose an `awaitProgress(timeoutMs)` helper, and call it (5 s budget) after the cold `didOpen` path for the `typescript` server. Verification: - `bun typecheck` clean. - `bun test test/lsp/` — 65 pass, 0 fail (7 new in `typescript-root.test.ts`: nested tsconfig, sibling sub-projects, tsconfig-over-lockfile priority, lockfile-only fallback, no-markers fallback, deno exclusion, distant-lockfile). - `bun test test/lsp/ test/tool/ test/config/` — 636 pass, 3 skip, 0 fail. Closes anomalyco#47174
Contributor
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #47174
Related to #40413, #35396, #18694 — the same change set addresses all three (the
Typescript.rootwalk covers #18694, thetsserver.jsresolution covers #35396, and the$/progresswait covers #40413). Maintainers can decide which to close as superseded when this lands.Type of change
What does this PR do?
The
lsptool returns empty results for.tsfiles in nested TypeScript sub-projects (each with its owntsconfig.jsonunder the working directory), and for some sub-projects it returns"No LSP server available for this file type."outright.Three defects in the LSP runtime compound to produce both symptoms.
Typescript.rootinpackages/opencode/src/lsp/server.tswalks up looking only for lockfiles, never fortsconfig.json. In a layout like the one in the issue (no lockfile at the workspace root), every.tsfile resolves toctx.directoryand all sub-projects share one tsserver client that never learns about the sub-project'stsconfig.json.Typescript.spawnresolvestypescript/lib/tsserver.jsfromctx.directoryviacreateRequire(path.join(dir, "package.json")). When the opencode working directory has nopackage.json, the call returnsundefinedand the key is marked broken, which is what produces the "No LSP server available" error.packages/opencode/src/lsp/client.tshas awindow/workDoneProgress/createhandler that returnsnull(silently dropping the progress token) and no$/progresslistener. typescript-language-server relays tsserver'sprojectLoadingStart/projectLoadingFinishas standard$/progressnotifications, so the first request races tsserver's project load and gets[].Changes:
packages/opencode/src/lsp/server.ts: include"tsconfig.json"inTypescript.root's include patterns (nearest wins, fully backward compatible) and resolvetsserver.jsfrom the sub-project root first with a fallback toctx.directory.packages/opencode/src/lsp/client.ts: return the token fromwindow/workDoneProgress/create, listen for$/progress, expose anawaitProgress(timeoutMs)helper, and call it (5 s budget) after the colddidOpenpath for thetypescriptserver.How did you verify your code works?
bun typecheckinpackages/opencodeis clean.bun test test/lsp/typescript-root.test.ts— 7 new tests covering nested tsconfig, sibling sub-projects resolving to distinct roots, tsconfig-over-lockfile priority, lockfile-only fallback, no-markers fallback, deno exclusion, and distant-lockfile.bun test test/lsp/ test/tool/ test/config/— 636 pass, 3 skip, 0 fail. Existingjdtls-root.test.ts,lsp/client.test.ts,lsp.test.ts(tool), andconfig/lsp.test.tsare all unaffected.End-to-end repro against the layout in #47174 (one scratch workspace with
frontend/,backend/,website/,sdk-ts/each containing atsconfig.json):documentSymbol,hover,goToDefinitiononfrontend/src/lib/services/query.service.tsreturns non-empty results.sdk-ts/src/client.tsno longer throw"No LSP server available for this file type.".bun run packages/opencode/src/cli/cmd/debug/lsp.ts statusreports two connectedtypescriptclients rooted at each sub-project (different cache keys pertsconfig.json).Screenshots / recordings
Not applicable — non-UI change.
Checklist