fix(lsp): typescript SDK install + tsc-missing skip + shellcheck warning (#24630)

Three follow-ups to PR #24168 found during live E2E testing on TS/bash files:

1. typescript-language-server now installs the typescript SDK (tsserver)
   alongside it. Without that sibling install, initialize() failed with
   "Could not find a valid TypeScript installation" and the server was
   marked broken — no diagnostics ever reached the agent. New extra_pkgs
   field on INSTALL_RECIPES makes that explicit and reusable for future
   peer-dep cases.

2. _check_lint now treats "linter command exists on PATH but cannot
   actually run" as skipped instead of error. The motivating case is
   npx tsc when typescript is not in node_modules — npx prints its
   "This is not the tsc command you are looking for" banner and exits
   non-zero, which previously blocked the LSP semantic tier (gated on
   success or skipped). Pattern-matched per base command (npx,
   rustfmt, go) so genuine lint errors still flow through normally.

3. hermes lsp status now surfaces a Backend warnings section when
   bash-language-server is installed but shellcheck is missing. The
   server itself spawns fine but bash-language-server delegates
   diagnostics to shellcheck — without it on PATH the integration
   looks alive but never reports any problems. Same warning is
   logged once at server spawn time.

Validation:

- 12 new tests in tests/agent/lsp/test_install_and_lint_fixes.py:
    * recipe carries typescript SDK
    * _install_npm passes both pkg + extras to npm CLI
    * backwards compat: recipes without extras still work
    * _backend_warnings quiet when bash absent / both present
    * _backend_warnings fires when bash installed without shellcheck
    * status output includes the Backend warnings section
    * _looks_like_linter_unusable catches the npx tsc banner
    * real TS type errors not misclassified as unusable
    * unfamiliar linters fall through normally
    * _check_lint returns skipped on npx tsc unusable
    * _check_lint returns error on real tsc type errors
- Full lsp + file_operations test suite: 245/245 pass
- Live E2E:
    * try_install("typescript-language-server") installs both packages
      into node_modules
    * write_file(bad.ts, ...) returns lint=skipped + lsp_diagnostics
      with two real TS errors (was lint=error, no lsp_diagnostics)
    * hermes lsp status renders the shellcheck warning when bash is
      installed but shellcheck is not on PATH
This commit is contained in:
Teknium 2026-05-12 17:02:35 -07:00 committed by GitHub
parent 6f285efb80
commit 29c9ff9ba5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 434 additions and 6 deletions

View file

@ -336,6 +336,9 @@ def _spawn_clangd(root: str, ctx: ServerContext) -> Optional[SpawnSpec]:
)
_BASH_SHELLCHECK_WARNED = False
def _spawn_bash_ls(root: str, ctx: ServerContext) -> Optional[SpawnSpec]:
bin_path = _resolve_override(ctx, "bash-language-server") or _which("bash-language-server")
if bin_path is None:
@ -343,6 +346,18 @@ def _spawn_bash_ls(root: str, ctx: ServerContext) -> Optional[SpawnSpec]:
bin_path = try_install("bash-language-server", ctx.install_strategy)
if bin_path is None:
return None
# bash-language-server delegates diagnostics to ``shellcheck``. Without
# it on PATH the server starts and accepts requests but never reports
# any problems — to the user it looks like a working integration that
# never finds bugs. Warn once so the gap is visible.
global _BASH_SHELLCHECK_WARNED
if not _BASH_SHELLCHECK_WARNED and _which("shellcheck") is None:
_BASH_SHELLCHECK_WARNED = True
logger.warning(
"bash-language-server: shellcheck not found on PATH — "
"diagnostics will be empty until shellcheck is installed "
"(apt: shellcheck, brew: shellcheck, scoop: shellcheck)."
)
return SpawnSpec(
command=[bin_path, "start"],
workspace_root=root,