refactor(core): replace legacy logger with Effect logging (#31310)

This commit is contained in:
Dax 2026-06-08 15:41:56 -04:00 committed by GitHub
commit c06ad7c881
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
152 changed files with 697 additions and 2242 deletions

View file

@ -2,7 +2,6 @@ import path from "path"
import { pathToFileURL, fileURLToPath } from "url"
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
import * as Log from "@opencode-ai/core/util/log"
import { Process } from "@/util/process"
import { LANGUAGE_EXTENSIONS } from "./language"
import { Effect, Schema } from "effect"
@ -23,7 +22,6 @@ const FILE_CHANGE_CREATED = 1
const FILE_CHANGE_CHANGED = 2
const TEXT_DOCUMENT_SYNC_INCREMENTAL = 2
const log = Log.create({ service: "lsp.client" })
export type Info = NonNullable<Awaited<ReturnType<typeof create>>>
export type Diagnostic = VSCodeDiagnostic
@ -129,23 +127,13 @@ export async function create(input: {
directory: string
instance: InstanceContext
}) {
const logger = log.clone().tag("serverID", input.serverID)
logger.info("starting client")
const instance = input.instance
const connection = createMessageConnection(
new StreamMessageReader(input.server.process.stdout as any),
new StreamMessageWriter(input.server.process.stdin as any),
)
// Server stderr can contain both real errors and routine informational logs,
// which is normal stderr practice for some tools. Keep the raw stream at
// debug so users can opt in with --print-logs --log-level DEBUG without
// polluting normal logs.
input.server.process.stderr?.on("data", (data: Buffer) => {
const text = data.toString().trim()
if (text) logger.debug("server stderr", { text: text.slice(0, 1000) })
})
input.server.process.stderr?.resume()
// --- Connection state ---
const pushDiagnostics = new Map<string, Diagnostic[]>()
@ -172,11 +160,6 @@ export async function create(input: {
connection.onNotification("textDocument/publishDiagnostics", (params) => {
const filePath = getFilePath(params.uri)
if (!filePath) return
logger.info("textDocument/publishDiagnostics", {
path: filePath,
count: params.diagnostics.length,
version: params.version,
})
published.set(filePath, {
at: Date.now(),
version: typeof params.version === "number" ? params.version : undefined,
@ -188,7 +171,6 @@ export async function create(input: {
updatePushDiagnostics(filePath, params.diagnostics)
})
connection.onRequest("window/workDoneProgress/create", (params) => {
logger.info("window/workDoneProgress/create", params)
return null
})
connection.onRequest("workspace/configuration", async (params) => {
@ -226,7 +208,6 @@ export async function create(input: {
// --- Initialize handshake ---
logger.info("sending initialize")
const initialized = await withTimeout(
connection.sendRequest<{ capabilities?: ServerCapabilities }>("initialize", {
rootUri: pathToFileURL(input.root).href,
@ -270,7 +251,6 @@ export async function create(input: {
}),
INITIALIZE_TIMEOUT_MS,
).catch((err) => {
logger.error("initialize error", { error: err })
throw new InitializeError({ serverID: input.serverID, cause: err })
})
@ -585,7 +565,6 @@ export async function create(input: {
// re-emit diagnostics when the content actually changes, so clearing
// here would lose errors for no-op touchFile calls. Let the server's
// next push/pull overwrite naturally.
logger.info("workspace/didChangeWatchedFiles", request)
await connection.sendNotification("workspace/didChangeWatchedFiles", {
changes: [
{
@ -597,10 +576,6 @@ export async function create(input: {
const next = document.version + 1
files[request.path] = { version: next, text }
logger.info("textDocument/didChange", {
path: request.path,
version: next,
})
await connection.sendNotification("textDocument/didChange", {
textDocument: {
uri: pathToFileURL(request.path).href,
@ -622,7 +597,6 @@ export async function create(input: {
return next
}
logger.info("workspace/didChangeWatchedFiles", request)
await connection.sendNotification("workspace/didChangeWatchedFiles", {
changes: [
{
@ -632,7 +606,6 @@ export async function create(input: {
],
})
logger.info("textDocument/didOpen", request)
pushDiagnostics.delete(request.path)
pullDiagnostics.delete(request.path)
await connection.sendNotification("textDocument/didOpen", {
@ -658,11 +631,6 @@ export async function create(input: {
const normalizedPath = Filesystem.normalizePath(
path.isAbsolute(request.path) ? request.path : path.resolve(input.directory, request.path),
)
logger.info("waiting for diagnostics", {
path: normalizedPath,
mode: request.mode ?? "full",
version: request.version,
})
if (request.mode === "document") {
await waitForDocumentDiagnostics({ path: normalizedPath, version: request.version, after: request.after })
return
@ -670,16 +638,12 @@ export async function create(input: {
await waitForFullDiagnostics({ path: normalizedPath, version: request.version, after: request.after })
},
async shutdown() {
logger.info("shutting down")
connection.end()
connection.dispose()
await Process.stop(input.server.process)
logger.info("shutdown")
},
}
logger.info("initialized")
return result
}