fix(lsp): MEMORY LEAK: ensure typescript server uses native project config (#19953)
parent
517e6c9aa4
commit
01f0319192
|
|
@ -105,7 +105,17 @@ export namespace LSPServer {
|
||||||
if (!tsserver) return
|
if (!tsserver) return
|
||||||
const bin = await Npm.which("typescript-language-server")
|
const bin = await Npm.which("typescript-language-server")
|
||||||
if (!bin) return
|
if (!bin) return
|
||||||
const proc = spawn(bin, ["--stdio"], {
|
|
||||||
|
const args = ["--stdio", "--tsserver-log-verbosity", "off", "--tsserver-path", tsserver]
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await pathExists(path.join(root, "tsconfig.json"))) &&
|
||||||
|
!(await pathExists(path.join(root, "jsconfig.json")))
|
||||||
|
) {
|
||||||
|
args.push("--ignore-node-modules")
|
||||||
|
}
|
||||||
|
|
||||||
|
const proc = spawn(bin, args, {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { describe, expect, spyOn, test } from "bun:test"
|
import { describe, expect, spyOn, test } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import fs from "fs/promises"
|
||||||
import * as Lsp from "../../src/lsp/index"
|
import * as Lsp from "../../src/lsp/index"
|
||||||
|
import * as launch from "../../src/lsp/launch"
|
||||||
import { LSPServer } from "../../src/lsp/server"
|
import { LSPServer } from "../../src/lsp/server"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
|
@ -52,4 +54,80 @@ describe("lsp.spawn", () => {
|
||||||
await Instance.disposeAll()
|
await Instance.disposeAll()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("spawns builtin Typescript LSP with correct arguments", async () => {
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
|
||||||
|
// Create dummy tsserver to satisfy Module.resolve
|
||||||
|
const tsdk = path.join(tmp.path, "node_modules", "typescript", "lib")
|
||||||
|
await fs.mkdir(tsdk, { recursive: true })
|
||||||
|
await fs.writeFile(path.join(tsdk, "tsserver.js"), "")
|
||||||
|
|
||||||
|
const spawnSpy = spyOn(launch, "spawn").mockImplementation(
|
||||||
|
() =>
|
||||||
|
({
|
||||||
|
stdin: {},
|
||||||
|
stdout: {},
|
||||||
|
stderr: {},
|
||||||
|
on: () => {},
|
||||||
|
kill: () => {},
|
||||||
|
}) as any,
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
await LSPServer.Typescript.spawn(tmp.path)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(spawnSpy).toHaveBeenCalled()
|
||||||
|
const args = spawnSpy.mock.calls[0][1] as string[]
|
||||||
|
|
||||||
|
expect(args).toContain("--tsserver-path")
|
||||||
|
expect(args).toContain("--tsserver-log-verbosity")
|
||||||
|
expect(args).toContain("off")
|
||||||
|
} finally {
|
||||||
|
spawnSpy.mockRestore()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test("spawns builtin Typescript LSP with --ignore-node-modules if no config is found", async () => {
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
|
||||||
|
// Create dummy tsserver to satisfy Module.resolve
|
||||||
|
const tsdk = path.join(tmp.path, "node_modules", "typescript", "lib")
|
||||||
|
await fs.mkdir(tsdk, { recursive: true })
|
||||||
|
await fs.writeFile(path.join(tsdk, "tsserver.js"), "")
|
||||||
|
|
||||||
|
// NO tsconfig.json or jsconfig.json created here
|
||||||
|
|
||||||
|
const spawnSpy = spyOn(launch, "spawn").mockImplementation(
|
||||||
|
() =>
|
||||||
|
({
|
||||||
|
stdin: {},
|
||||||
|
stdout: {},
|
||||||
|
stderr: {},
|
||||||
|
on: () => {},
|
||||||
|
kill: () => {},
|
||||||
|
}) as any,
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
await LSPServer.Typescript.spawn(tmp.path)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(spawnSpy).toHaveBeenCalled()
|
||||||
|
const args = spawnSpy.mock.calls[0][1] as string[]
|
||||||
|
|
||||||
|
expect(args).toContain("--ignore-node-modules")
|
||||||
|
} finally {
|
||||||
|
spawnSpy.mockRestore()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
|
||||||
| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions for non-interactive shell commands - prevents hangs from TTY-dependent operations |
|
| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions for non-interactive shell commands - prevents hangs from TTY-dependent operations |
|
||||||
| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Track OpenCode usage with Wakatime |
|
| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Track OpenCode usage with Wakatime |
|
||||||
| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs |
|
| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs |
|
||||||
|
| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x faster code editing with Morph Fast Apply API and lazy edit markers |
|
||||||
| [opencode-morph-plugin](https://github.com/morphllm/opencode-morph-plugin) | Fast Apply editing, WarpGrep codebase search, and context compaction via Morph |
|
| [opencode-morph-plugin](https://github.com/morphllm/opencode-morph-plugin) | Fast Apply editing, WarpGrep codebase search, and context compaction via Morph |
|
||||||
| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible |
|
| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible |
|
||||||
| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop notifications and sound alerts for OpenCode sessions |
|
| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop notifications and sound alerts for OpenCode sessions |
|
||||||
|
|
@ -42,6 +43,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
|
||||||
| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interactive plan review with visual annotation and private/offline sharing |
|
| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interactive plan review with visual annotation and private/offline sharing |
|
||||||
| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Extend opencode /commands into a powerful orchestration system with granular flow control |
|
| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Extend opencode /commands into a powerful orchestration system with granular flow control |
|
||||||
| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Schedule recurring jobs using launchd (Mac) or systemd (Linux) with cron syntax |
|
| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Schedule recurring jobs using launchd (Mac) or systemd (Linux) with cron syntax |
|
||||||
|
| [opencode-conductor](https://github.com/derekbar90/opencode-conductor) | Protocol-Driven Workflow: Automation of the Context -> Spec -> Plan -> Implement lifecycle. |
|
||||||
| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement workflow with session continuity |
|
| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement workflow with session continuity |
|
||||||
| [octto](https://github.com/vtemian/octto) | Interactive browser UI for AI brainstorming with multi-question forms |
|
| [octto](https://github.com/vtemian/octto) | Interactive browser UI for AI brainstorming with multi-question forms |
|
||||||
| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code-style background agents with async delegation and context persistence |
|
| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code-style background agents with async delegation and context persistence |
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue