Skip to content

fix(opencode): resolve LSP for nested TypeScript sub-projects - #47181

Open
joao-jlcm wants to merge 1 commit into
anomalyco:devfrom
joao-jlcm:fix-lsp-tsconfig
Open

fix(opencode): resolve LSP for nested TypeScript sub-projects#47181
joao-jlcm wants to merge 1 commit into
anomalyco:devfrom
joao-jlcm:fix-lsp-tsconfig

Conversation

@joao-jlcm

@joao-jlcm joao-jlcm commented Sep 4, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #47174

Related to #40413, #35396, #18694 — the same change set addresses all three (the Typescript.root walk covers #18694, the tsserver.js resolution covers #35396, and the $/progress wait covers #40413). Maintainers can decide which to close as superseded when this lands.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The lsp tool returns empty results for .ts files in nested TypeScript sub-projects (each with its own tsconfig.json under 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.root in packages/opencode/src/lsp/server.ts walks up looking only for lockfiles, never for tsconfig.json. In a layout like the one in the issue (no lockfile at the workspace root), every .ts file resolves to ctx.directory and all sub-projects share one tsserver client that never learns about the sub-project's tsconfig.json.

Typescript.spawn resolves typescript/lib/tsserver.js from ctx.directory via createRequire(path.join(dir, "package.json")). When the opencode working directory has no package.json, the call returns undefined and the key is marked broken, which is what produces the "No LSP server available" error.

packages/opencode/src/lsp/client.ts has a window/workDoneProgress/create handler that returns null (silently dropping the progress token) and no $/progress listener. typescript-language-server relays tsserver's projectLoadingStart / projectLoadingFinish as standard $/progress notifications, so the first request races tsserver's project load and gets [].

Changes:

  • 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.

How did you verify your code works?

  • bun typecheck in packages/opencode is 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. Existing jdtls-root.test.ts, lsp/client.test.ts, lsp.test.ts (tool), and config/lsp.test.ts are all unaffected.

End-to-end repro against the layout in #47174 (one scratch workspace with frontend/, backend/, website/, sdk-ts/ each containing a tsconfig.json):

  • documentSymbol, hover, goToDefinition on frontend/src/lib/services/query.service.ts returns non-empty results.
  • Same operations on sdk-ts/src/client.ts no longer throw "No LSP server available for this file type.".
  • bun run packages/opencode/src/cli/cmd/debug/lsp.ts status reports two connected typescript clients rooted at each sub-project (different cache keys per tsconfig.json).

Screenshots / recordings

Not applicable — non-UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

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
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lsp tool returns empty results for TypeScript files in nested sub-projects (multiple tsconfig roots) under the working directory

1 participant