Skip to content

feat: add a typescript-language-server feature - #15

Merged
ashwin153 merged 2 commits into
mainfrom
claude/typescript-lsp-devcontainer-q4puln
Aug 17, 2026
Merged

feat: add a typescript-language-server feature#15
ashwin153 merged 2 commits into
mainfrom
claude/typescript-lsp-devcontainer-q4puln

Conversation

@ashwin153

@ashwin153 ashwin153 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Softlight Overview

UX Score: 5/5

Softlight reviewed this change and found no issues.

To run Softlight again, click here or comment @softlight.

Adds a typescript-language-server feature that installs the TypeScript language server for LSP clients — anything that spawns typescript-language-server --stdio, such as editors and Claude Code's TypeScript LSP plugin.

Surviving nvm use

Same shape #14 gave playwright-cli: the server installs under its own prefix, /usr/local/share/typescript-language-server, with the binary symlinked into /usr/local/bin. A plain npm install --global would land in the active node version's directory under $NVM_DIR, so nvm install / nvm use would drop it off PATH for the whole container. One copy now backs every node version, stays root-owned and read-only to the remote user, and runs on whatever node is active (the package needs node 20+). As with playwright-cli, sudo is unsupported.

The tsserver fallback

typescript-language-server bundles no typescript and refuses to initialize without one, so the feature installs a typescript into the same prefix; the server resolves it as its fallback whenever the workspace has no node_modules/typescript, and a workspace copy still wins when present.

The fallback pins major 6, not latest: TypeScript 7 is the native-compiler rewrite that ships no lib/tsserver.js — the module this server runs — and a server pointed at it dies on initialize with "Could not find a valid TypeScript installation". The install script checks for lib/tsserver.js and fails the build loudly when the pinned typescriptVersion cannot back the server.

Verification

Ran the install script and drove a real LSP session against a workspace with no typescript dependency: the server initializes, logs Using Typescript version (bundled) 6.0.3 from path ".../typescript/lib/tsserver.js", and publishes a genuine diagnostic (Type 'string' is not assignable to type 'number'). Pointing typescriptVersion at latest (7.0.2) fails the install with the explicit tsserver.js error. Scenario checks mirror the playwright ones — resolved binary outside $NVM_DIR, read-only shared install, survives a node version switch — plus one that replicates the server's fallback lookup and asserts tsserver.js exists where it will look. pre-commit run --all-files passes.

Once published, consuming it from the devcontainer repo is:

"ghcr.io/orianna-ai/devcontainer-features/typescript-language-server:1": {}

🤖 Generated with Claude Code

https://claude.ai/code/session_01JKLMf5r9nLWUko79PA91RM


Generated by Claude Code


Note

Cursor Bugbot is generating a summary for commit 610a779. Configure here.

Greptile Summary

The PR adds a devcontainer feature that installs typescript-language-server and a compatible fallback TypeScript compiler in a shared prefix that survives Node version switches.

  • Adds configurable language-server and fallback TypeScript versions.
  • Validates that the fallback package contains lib/tsserver.js.
  • Adds scenario coverage for installation ownership, fallback resolution, Node switching, and a real diagnostic-producing LSP session.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/typescript-language-server/install.sh Installs the server and fallback compiler into a root-owned shared prefix, validates tsserver availability, and exposes only the language-server binary.
src/typescript-language-server/devcontainer-feature.json Defines the feature metadata, installation ordering, and configurable server and compiler versions.
test/typescript-language-server/ubuntu.sh Verifies fallback resolution and now exercises a complete LSP initialization and diagnostic flow without a workspace TypeScript dependency.
test/typescript-language-server/scenarios.json Configures the Ubuntu scenario with Node and common-utils prerequisites.

Reviews (2): Last reviewed commit: "fix: fail the build on an incompatible n..." | Re-trigger Greptile

Installs the TypeScript language server for LSP clients — anything that spawns
"typescript-language-server --stdio", such as editors and Claude Code's TypeScript LSP plugin. It
follows the shape 81f5072 gave playwright-cli: installed under its own prefix,
/usr/local/share/typescript-language-server, and symlinked into /usr/local/bin, so "nvm install" or
"nvm use" repointing $NVM_DIR/current cannot drop it off PATH; the install stays root-owned and
read-only to the remote user, and sudo remains unsupported for the same reasons as there.

typescript-language-server bundles no typescript of its own and refuses to initialize without one,
so the feature installs a typescript into the same prefix; the server resolves it as its fallback
whenever the workspace has no node_modules/typescript, and a workspace copy still wins when present.
The fallback pins major 6 rather than latest: TypeScript 7 is the native-compiler rewrite that ships
no lib/tsserver.js, which is the module this server runs, and a server pointed at it dies on
initialize with "Could not find a valid TypeScript installation". The install checks for
lib/tsserver.js and fails loudly when the pinned version cannot back the server.

Verified end to end against a workspace with no typescript dependency: the server initializes,
logs 'Using Typescript version (bundled) 6.0.3', and publishes a real diagnostic ("Type 'string' is
not assignable to type 'number'"); pointing typescriptVersion at latest fails the install with the
explicit tsserver.js error. The scenario checks mirror the playwright ones — resolved binary outside
$NVM_DIR, read-only shared install, survives a node version switch — plus one that replicates the
server's fallback lookup and asserts tsserver.js exists where it will look.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKLMf5r9nLWUko79PA91RM
Comment thread test/typescript-language-server/ubuntu.sh
Two review findings, both taken.

npm treats a package's engines declaration as a warning, so building with a node older than the
server supports (the current line needs 20+) produced an image whose language server cannot start.
The install now passes --engine-strict, turning that into npm's explicit build-time engine error —
the same fail-loudly posture as the tsserver.js check. An expect-failure scenario is not something
the feature test harness can express, so the guard is exercised only implicitly by the passing
scenarios.

The scenario checks proved the fallback typescript resolves from the server tree but never started
the server against it, which is exactly the gap that would have hidden the typescript@7
incompatibility: resolution succeeds, initialize dies. The suite now drives a real LSP session from
a workspace with no typescript dependency — initialize, didOpen a file with a type error, wait for
publishDiagnostics — and passes only when a genuine diagnostic comes back from the fallback
compiler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKLMf5r9nLWUko79PA91RM

Copy link
Copy Markdown
Contributor Author

@greptileai


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

@softlight


Generated by Claude Code

@ashwin153
ashwin153 merged commit 46b22ee into main Aug 17, 2026
4 checks passed
@ashwin153
ashwin153 deleted the claude/typescript-lsp-devcontainer-q4puln branch August 17, 2026 17:20
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.

2 participants