Files
oh-my-opencode/src/tools/lsp/diagnostics-tool.ts
T
2026-04-04 01:27:51 +09:00

76 lines
2.6 KiB
TypeScript

import { resolve } from "path"
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
import { DEFAULT_MAX_DIAGNOSTICS } from "./constants"
import { aggregateDiagnosticsForDirectory } from "./directory-diagnostics"
import { inferExtensionFromDirectory } from "./infer-extension"
import { filterDiagnosticsBySeverity, formatDiagnostic } from "./lsp-formatters"
import { isDirectoryPath, withLspClient } from "./lsp-client-wrapper"
import type { Diagnostic } from "./types"
export const lsp_diagnostics: ToolDefinition = tool({
description:
'Get errors, warnings, hints from language server BEFORE running build. Works for both single files and directories - file extension is auto-detected for directories.',
args: {
filePath: tool.schema
.string()
.describe("File or directory path to check diagnostics for"),
severity: tool.schema
.enum(["error", "warning", "information", "hint", "all"])
.optional()
.describe("Filter by severity level"),
},
execute: async (args, _context) => {
try {
if (!args.filePath) {
throw new Error("'filePath' parameter is required.")
}
const absPath = resolve(args.filePath)
if (isDirectoryPath(absPath)) {
const extension = inferExtensionFromDirectory(absPath)
if (!extension) {
throw new Error(
`No supported source files found in directory: ${absPath}`
)
}
return await aggregateDiagnosticsForDirectory(absPath, extension, args.severity)
}
const result = await withLspClient(args.filePath, async (client) => {
return (await client.diagnostics(args.filePath)) as { items?: Diagnostic[] } | Diagnostic[] | null
})
let diagnostics: Diagnostic[] = []
if (result) {
if (Array.isArray(result)) {
diagnostics = result
} else if (result.items) {
diagnostics = result.items
}
}
diagnostics = filterDiagnosticsBySeverity(diagnostics, args.severity)
if (diagnostics.length === 0) {
const output = "No diagnostics found"
return output
}
const total = diagnostics.length
const truncated = total > DEFAULT_MAX_DIAGNOSTICS
const limited = truncated ? diagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS) : diagnostics
const lines = limited.map(formatDiagnostic)
if (truncated) {
lines.unshift(`Found ${total} diagnostics (showing first ${DEFAULT_MAX_DIAGNOSTICS}):`)
}
const output = lines.join("\n")
return output
} catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}`
throw new Error(output)
}
},
})