feat: add a typescript-language-server feature - #15
Merged
Conversation
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
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
Contributor
Author
|
Generated by Claude Code |
Contributor
Author
|
Generated by Claude Code |
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.
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-serverfeature that installs the TypeScript language server for LSP clients — anything that spawnstypescript-language-server --stdio, such as editors and Claude Code's TypeScript LSP plugin.Surviving
nvm useSame 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 plainnpm install --globalwould land in the active node version's directory under$NVM_DIR, sonvm install/nvm usewould drop it offPATHfor 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,sudois unsupported.The tsserver fallback
typescript-language-serverbundles notypescriptand refuses to initialize without one, so the feature installs atypescriptinto the same prefix; the server resolves it as its fallback whenever the workspace has nonode_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 nolib/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 forlib/tsserver.jsand fails the build loudly when the pinnedtypescriptVersioncannot 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'). PointingtypescriptVersionatlatest(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 assertstsserver.jsexists where it will look.pre-commit run --all-filespasses.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-serverand a compatible fallback TypeScript compiler in a shared prefix that survives Node version switches.lib/tsserver.js.Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Important Files Changed
Reviews (2): Last reviewed commit: "fix: fail the build on an incompatible n..." | Re-trigger Greptile