refactor(doctor): show detected LSP servers and extensions instead of hardcoded counts
Replace the hardcoded 4-server list in doctor LSP check with getAllServers()
from server-resolution.ts, which covers all 40+ builtin servers plus user
config. Output now shows server count with supported extensions, and verbose
mode expands to per-server detail lines.
Status: LSP 3 servers (.go, .py, .pyi, .ts, .tsx)
Verbose: LSP 3 servers (.go, .py, .pyi, .ts, .tsx)
typescript (.ts, .tsx, .js, .jsx)
pyright (.py, .pyi)
gopls (.go)
Closes #2587
This commit is contained in:
@@ -1,25 +1,9 @@
|
|||||||
import type { LspServerInfo } from "../types"
|
import { getAllServers } from "../../../tools/lsp/config"
|
||||||
import { isServerInstalled } from "../../../tools/lsp/config"
|
|
||||||
|
|
||||||
const DEFAULT_LSP_SERVERS: Array<{ id: string; binary: string; extensions: string[] }> = [
|
export function getInstalledLspServers(): Array<{ id: string; extensions: string[] }> {
|
||||||
{ id: "typescript-language-server", binary: "typescript-language-server", extensions: [".ts", ".tsx", ".js", ".jsx"] },
|
const servers = getAllServers()
|
||||||
{ id: "pyright", binary: "pyright-langserver", extensions: [".py"] },
|
|
||||||
{ id: "rust-analyzer", binary: "rust-analyzer", extensions: [".rs"] },
|
|
||||||
{ id: "gopls", binary: "gopls", extensions: [".go"] },
|
|
||||||
]
|
|
||||||
|
|
||||||
export function getLspServersInfo(): LspServerInfo[] {
|
return servers
|
||||||
return DEFAULT_LSP_SERVERS.map((server) => ({
|
.filter((s) => s.installed && !s.disabled)
|
||||||
id: server.id,
|
.map((s) => ({ id: s.id, extensions: s.extensions }))
|
||||||
installed: isServerInstalled([server.binary]),
|
|
||||||
extensions: server.extensions,
|
|
||||||
source: "builtin",
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getLspServerStats(servers: LspServerInfo[]): { installed: number; total: number } {
|
|
||||||
return {
|
|
||||||
installed: servers.filter((server) => server.installed).length,
|
|
||||||
total: servers.length,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { checkAstGrepCli, checkAstGrepNapi, checkCommentChecker } from "./dependencies"
|
import { checkAstGrepCli, checkAstGrepNapi, checkCommentChecker } from "./dependencies"
|
||||||
import { getGhCliInfo } from "./tools-gh"
|
import { getGhCliInfo } from "./tools-gh"
|
||||||
import { getLspServerStats, getLspServersInfo } from "./tools-lsp"
|
import { getInstalledLspServers } from "./tools-lsp"
|
||||||
import { getBuiltinMcpInfo, getUserMcpInfo } from "./tools-mcp"
|
import { getBuiltinMcpInfo, getUserMcpInfo } from "./tools-mcp"
|
||||||
import { CHECK_IDS, CHECK_NAMES } from "../constants"
|
import { CHECK_IDS, CHECK_NAMES } from "../constants"
|
||||||
import type { CheckResult, DoctorIssue, ToolsSummary } from "../types"
|
import type { CheckResult, DoctorIssue, ToolsSummary } from "../types"
|
||||||
@@ -13,14 +13,12 @@ export async function gatherToolsSummary(): Promise<ToolsSummary> {
|
|||||||
getGhCliInfo(),
|
getGhCliInfo(),
|
||||||
])
|
])
|
||||||
|
|
||||||
const lspServers = getLspServersInfo()
|
const lspServers = getInstalledLspServers()
|
||||||
const lspStats = getLspServerStats(lspServers)
|
|
||||||
const builtinMcp = getBuiltinMcpInfo()
|
const builtinMcp = getBuiltinMcpInfo()
|
||||||
const userMcp = getUserMcpInfo()
|
const userMcp = getUserMcpInfo()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lspInstalled: lspStats.installed,
|
lspServers,
|
||||||
lspTotal: lspStats.total,
|
|
||||||
astGrepCli: astGrepCliInfo.installed,
|
astGrepCli: astGrepCliInfo.installed,
|
||||||
astGrepNapi: astGrepNapiInfo.installed,
|
astGrepNapi: astGrepNapiInfo.installed,
|
||||||
commentChecker: commentCheckerInfo.installed,
|
commentChecker: commentCheckerInfo.installed,
|
||||||
@@ -57,7 +55,7 @@ function buildToolIssues(summary: ToolsSummary): DoctorIssue[] {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summary.lspInstalled === 0) {
|
if (summary.lspServers.length === 0) {
|
||||||
issues.push({
|
issues.push({
|
||||||
title: "No LSP servers detected",
|
title: "No LSP servers detected",
|
||||||
description: "LSP-dependent tools will be limited until at least one server is installed.",
|
description: "LSP-dependent tools will be limited until at least one server is installed.",
|
||||||
@@ -109,7 +107,7 @@ export async function checkTools(): Promise<CheckResult> {
|
|||||||
details: [
|
details: [
|
||||||
`AST-Grep: cli=${summary.astGrepCli ? "yes" : "no"}, napi=${summary.astGrepNapi ? "yes" : "no"}`,
|
`AST-Grep: cli=${summary.astGrepCli ? "yes" : "no"}, napi=${summary.astGrepNapi ? "yes" : "no"}`,
|
||||||
`Comment checker: ${summary.commentChecker ? "yes" : "no"}`,
|
`Comment checker: ${summary.commentChecker ? "yes" : "no"}`,
|
||||||
`LSP: ${summary.lspInstalled}/${summary.lspTotal}`,
|
`LSP: ${summary.lspServers.length > 0 ? `${summary.lspServers.length} server(s)` : "none"}`,
|
||||||
`GH CLI: ${summary.ghCli.installed ? "installed" : "missing"}${summary.ghCli.authenticated ? " (authenticated)" : ""}`,
|
`GH CLI: ${summary.ghCli.installed ? "installed" : "missing"}${summary.ghCli.authenticated ? " (authenticated)" : ""}`,
|
||||||
`MCP: builtin=${summary.mcpBuiltin.length}, user=${summary.mcpUser.length}`,
|
`MCP: builtin=${summary.mcpBuiltin.length}, user=${summary.mcpUser.length}`,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ function createBaseResult(): DoctorResult {
|
|||||||
isLocalDev: false,
|
isLocalDev: false,
|
||||||
},
|
},
|
||||||
tools: {
|
tools: {
|
||||||
lspInstalled: 0,
|
lspServers: [],
|
||||||
lspTotal: 0,
|
|
||||||
astGrepCli: false,
|
astGrepCli: false,
|
||||||
astGrepNapi: false,
|
astGrepNapi: false,
|
||||||
commentChecker: false,
|
commentChecker: false,
|
||||||
|
|||||||
@@ -19,11 +19,13 @@ export function formatStatus(result: DoctorResult): string {
|
|||||||
const configStatus = systemInfo.configValid ? color.green("(valid)") : color.red("(invalid)")
|
const configStatus = systemInfo.configValid ? color.green("(valid)") : color.red("(invalid)")
|
||||||
lines.push(` ${padding}Config ${configPath} ${configStatus}`)
|
lines.push(` ${padding}Config ${configPath} ${configStatus}`)
|
||||||
|
|
||||||
const lspText = `LSP ${tools.lspInstalled}/${tools.lspTotal}`
|
const serverCount = tools.lspServers.length
|
||||||
|
const lspMark = formatStatusMark(serverCount > 0)
|
||||||
|
const lspText = serverCount > 0 ? `${serverCount} server${serverCount === 1 ? "" : "s"}` : "none"
|
||||||
const astGrepMark = formatStatusMark(tools.astGrepCli)
|
const astGrepMark = formatStatusMark(tools.astGrepCli)
|
||||||
const ghMark = formatStatusMark(tools.ghCli.installed && tools.ghCli.authenticated)
|
const ghMark = formatStatusMark(tools.ghCli.installed && tools.ghCli.authenticated)
|
||||||
const ghUser = tools.ghCli.username ?? ""
|
const ghUser = tools.ghCli.username ?? ""
|
||||||
lines.push(` ${padding}Tools ${lspText} · AST-Grep ${astGrepMark} · gh ${ghMark}${ghUser ? ` (${ghUser})` : ""}`)
|
lines.push(` ${padding}Tools LSP ${lspMark} ${lspText} · AST-Grep ${astGrepMark} · gh ${ghMark}${ghUser ? ` (${ghUser})` : ""}`)
|
||||||
|
|
||||||
const builtinCount = tools.mcpBuiltin.length
|
const builtinCount = tools.mcpBuiltin.length
|
||||||
const userCount = tools.mcpUser.length
|
const userCount = tools.mcpUser.length
|
||||||
|
|||||||
@@ -33,7 +33,15 @@ export function formatVerbose(result: DoctorResult): string {
|
|||||||
|
|
||||||
lines.push(`${color.bold("Tools")}`)
|
lines.push(`${color.bold("Tools")}`)
|
||||||
lines.push(`${color.dim("\u2500".repeat(40))}`)
|
lines.push(`${color.dim("\u2500".repeat(40))}`)
|
||||||
lines.push(` ${formatStatusSymbol("pass")} LSP ${tools.lspInstalled}/${tools.lspTotal} installed`)
|
if (tools.lspServers.length === 0) {
|
||||||
|
lines.push(` ${formatStatusSymbol("warn")} LSP none detected`)
|
||||||
|
} else {
|
||||||
|
const allExts = [...new Set(tools.lspServers.flatMap((s) => s.extensions))].sort()
|
||||||
|
lines.push(` ${formatStatusSymbol("pass")} LSP ${tools.lspServers.length} server${tools.lspServers.length === 1 ? "" : "s"} (${allExts.join(", ")})`)
|
||||||
|
for (const server of tools.lspServers) {
|
||||||
|
lines.push(`${" ".repeat(20)}${server.id} (${server.extensions.join(", ")})`)
|
||||||
|
}
|
||||||
|
}
|
||||||
lines.push(` ${formatStatusSymbol(tools.astGrepCli ? "pass" : "fail")} ast-grep CLI ${tools.astGrepCli ? "installed" : "not found"}`)
|
lines.push(` ${formatStatusSymbol(tools.astGrepCli ? "pass" : "fail")} ast-grep CLI ${tools.astGrepCli ? "installed" : "not found"}`)
|
||||||
lines.push(` ${formatStatusSymbol(tools.astGrepNapi ? "pass" : "fail")} ast-grep napi ${tools.astGrepNapi ? "installed" : "not found"}`)
|
lines.push(` ${formatStatusSymbol(tools.astGrepNapi ? "pass" : "fail")} ast-grep napi ${tools.astGrepNapi ? "installed" : "not found"}`)
|
||||||
lines.push(` ${formatStatusSymbol(tools.commentChecker ? "pass" : "fail")} comment-checker ${tools.commentChecker ? "installed" : "not found"}`)
|
lines.push(` ${formatStatusSymbol(tools.commentChecker ? "pass" : "fail")} comment-checker ${tools.commentChecker ? "installed" : "not found"}`)
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ function createDoctorResult(): DoctorResult {
|
|||||||
isLocalDev: false,
|
isLocalDev: false,
|
||||||
},
|
},
|
||||||
tools: {
|
tools: {
|
||||||
lspInstalled: 2,
|
lspServers: [
|
||||||
lspTotal: 4,
|
{ id: "typescript", extensions: [".ts", ".tsx", ".js", ".jsx"] },
|
||||||
|
{ id: "pyright", extensions: [".py", ".pyi"] },
|
||||||
|
],
|
||||||
astGrepCli: true,
|
astGrepCli: true,
|
||||||
astGrepNapi: false,
|
astGrepNapi: false,
|
||||||
commentChecker: true,
|
commentChecker: true,
|
||||||
@@ -102,7 +104,7 @@ describe("formatDoctorOutput", () => {
|
|||||||
const output = stripAnsi(formatDoctorOutput(result, "status"))
|
const output = stripAnsi(formatDoctorOutput(result, "status"))
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(output).toContain("LSP 2/4")
|
expect(output).toContain("LSP")
|
||||||
expect(output).toContain("context7")
|
expect(output).toContain("context7")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ function createSystemInfo(): SystemInfo {
|
|||||||
|
|
||||||
function createTools(): ToolsSummary {
|
function createTools(): ToolsSummary {
|
||||||
return {
|
return {
|
||||||
lspInstalled: 1,
|
lspServers: [{ id: "typescript", extensions: [".ts", ".tsx", ".js", ".jsx"] }],
|
||||||
lspTotal: 4,
|
|
||||||
astGrepCli: true,
|
astGrepCli: true,
|
||||||
astGrepNapi: false,
|
astGrepNapi: false,
|
||||||
commentChecker: true,
|
commentChecker: true,
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ export interface SystemInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolsSummary {
|
export interface ToolsSummary {
|
||||||
lspInstalled: number
|
lspServers: Array<{ id: string; extensions: string[] }>
|
||||||
lspTotal: number
|
|
||||||
astGrepCli: boolean
|
astGrepCli: boolean
|
||||||
astGrepNapi: boolean
|
astGrepNapi: boolean
|
||||||
commentChecker: boolean
|
commentChecker: boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user