fix(lsp): address codex review round 1
Lifecycle and safety fixes from the external review: - Observe abort while awaiting the initialize handshake, so a server that never replies can't defeat the tool-timeout signal. - On an aborted request the server won't cancel, tear the instance down after a bounded grace instead of releasing the serialized queue with work still live (prevents overlapping document lifecycles). - Re-check provider disposal after the canonicalize/read awaits so a query can't spawn an unowned server after disposeAll(). - Read the source through one open handle (stat + read on the same fd) to close the realpath-vs-read TOCTOU; decode with a fatal UTF-8 decoder so a legitimate U+FFFD is not misclassified as invalid. - Validate and read the source BEFORE spawning a server (pre-start rejection). - Require an explicit openClose for option-form textDocumentSync. - Reject nonpositive teardown budgets and non-executable absolute commands at load; surface unsupported operations as structured LSP_UNSUPPORTED_OPERATION. - Retain the stderr tail (fatal diagnostics land at exit), not the prefix. - Catalog the seam vocabulary in docs/core-data-structures/lsp.md.
This commit is contained in:
@@ -174,8 +174,9 @@ export class LspConnection {
|
||||
}
|
||||
|
||||
private onStderr(chunk: Buffer): void {
|
||||
if (this.stderr.length >= this.spec.maxStderrBytes) return
|
||||
this.stderr = (this.stderr + chunk.toString('utf8')).slice(0, this.spec.maxStderrBytes)
|
||||
// Retain the TAIL, not the prefix: a language server's fatal diagnostic usually appears just
|
||||
// before it exits, so the final bounded segment is the useful one.
|
||||
this.stderr = (this.stderr + chunk.toString('utf8')).slice(-this.spec.maxStderrBytes)
|
||||
}
|
||||
|
||||
private dispatch(message: unknown): void {
|
||||
|
||||
Reference in New Issue
Block a user