# @effected/lsp 中文文档

规范地址：https://npmcn.com/package/%40effected/lsp/

版本：0\.9\.0
npm 元数据更新时间：2026-11-10T15:20:50.822Z
中文译文更新时间：2026-11-13T12:43:47.572Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40effected/lsp
原文对照：https://npmcn.com/package/%40effected/lsp/?lang=original
项目主页：https://github.com/spencerbeggs/effected/tree/main/packages/lsp#readme
源码仓库：https://github.com/spencerbeggs/effected

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：101 kB，16 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=24\.11\.0
- 运行依赖：0 个
- peer 依赖：effect ~4\.1\.0
- 首次发布：2026-10-05T22:34:46.072Z
- 最新版本发布：2026-11-10T15:20:50.484Z
- 近 30 天下载量：3954（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：12（近 12 个月 12 个）

## 中文简介

Effect v4 语言服务器协议基础- protocol 框架,外加一个装入的安装初始化探测器,用于语言服务器本

## 安装

```sh
npm install @effected/lsp
```

也可以使用：`pnpm add @effected/lsp`、`yarn add @effected/lsp`、`bun add @effected/lsp`

## README

# @ effect/ lsp

Effect v4 语言服务器协议基础-protocol框架 - `Content-Length` 框由字节长度编码,并逐步解码——一个Stdio发射装置,使LSP线条和出口保持有规格要求的代码,a `./testing` 其子路径 `LspProbe` 证明语言服务器的 bin 靴子 `LspProcess` 逐帧驱动.

[![npm](https://img.shields.io/npm/v/@effected%2Flsp?label=npm&color=cb3837)](https://www.npmjs.com/package/@effected/lsp) [![License: MIT](https://img.shields.io/badge/License-MIT-4caf50.svg)](https://opensource.org/licenses/MIT) [![Node.js %3E%3D24.11.0](https://img.shields.io/badge/Node.js-%3E%3D24.11.0-5fa04e.svg)](https://nodejs.org/) [![TypeScript 7.0](https://img.shields.io/badge/TypeScript-7.0-3178c6.svg)](https://www.typescriptlang.org/)

> **预`1.0.0`。 。 。 .** 此软件包是 `@effected/*` 在稳定基础上建造的工具包 效应v4(`effect` `~4.1.0`) 并仍在 `0.x` 发展。 稳定效果 制作一个工具箱 `1.0.0` 可能,不是自动的。 为了保持你的 `effect` 财务报告和审定财务报表 `@effect/*` 该工具包在线上构建和测试、安装 [`@effected/pnpm-plugin-effected`](https://www.npmjs.com/package/@effected/pnpm-plugin-effected)。 。 。 .
> 
> **稳定:不稳定.** 此软件包的 API 表面尚未考虑 完成并可能改变 `0.x` 释放 定一个确切的版本——甚至 标记软件包 _稳定_ 在此之前 `1.0.0` 可以引入突破性更改 和精确的针 变成一个类型检查错误 而不是一个 跑步时间惊喜。 完全政策: [释放策略](https://github.com/spencerbeggs/effected#release-strategy)。 。 。 .

## 安装

```bash
npm install @effected/lsp effect
```

```bash
pnpm add @effected/lsp effect
```

需要节点.js~~24.11.0.

全体 `@effected/*` 软件包仅为无害环境管理:只公布出口地图 `import` 条件,所以 `require()` 节点失败 `ERR_PACKAGE_PATH_NOT_EXPORTED`从ES模块导入.

`effect` v4是唯一的对等依赖. 边界分级:主要输入是纯的,以及 `./testing` 只通过核心运行一个儿童进程 `ChildProcessSpawner`,您提供一个平台层(`NodeServices.layer` 从 `@effect/platform-node`) (中文(简体) ).

这不是 LSP 服务器框架 。 它会设定线条, 发射一个您所写的服务器, 并测试本站; 消息循环和每个处理器 都与您所服务的协议一起 .

## 长发

LSP信息作为头条块、空白行和UTF-8 JSON的躯体而行走 `Content-Length` 计数 **字节**。一个手卷框,写着 `body.length` 对 ASCII 是正确的,对多字节字符的每个多字节字节都错误一个字节,所以服务器读取到下一个框架. `LspFrame.encode` 计数编码 :

```ts
import { LspFrame } from "@effected/lsp";

const frame = LspFrame.encode({ jsonrpc: "2.0", method: "note", params: { text: "✓" } });
console.log(new TextDecoder().decode(frame));
// => Content-Length: 57
//
//    {"jsonrpc":"2.0","method":"note","params":{"text":"✓"}}
```

解码是渐进的. `LspFrame.decodeResult` 取出任何已到达的字节,然后返回每个完整的框加上一个不完整的框的字节,所以一个块可能会在一个头,一个正体或一个字符内结束,并可能携带几个框. `LspFrame.decodeStream` 横穿一线 `Stream` 块,和 `LspFrame.decodeAllResult` 解码一个收集的 stdout in one go:

```ts
import { LspFrame } from "@effected/lsp";
import { Result } from "effect";

const decoded = LspFrame.decodeAllResult('Content-Length: 2\r\n\r\n{}Content-Length: 5\r\n\r\n"✓"');
console.log(Result.getOrThrow(decoded));
// => [ {}, '✓' ]
```

输入的流格式错误失败 `LspFrameError` 谁 `code` 说哪条规则被打破了`MissingContentLength`, (中文(简体) ), `InvalidContentLength`, (中文(简体) ), `InvalidHeader`, (中文(简体) ), `HeaderTooLarge`, (中文(简体) ), `InvalidBody`, (中文(简体) ), `Truncated`(b) 其国家 `offset` 是框架的溪流位置,并且 `excerpt` 呼应了帧的起步——在第一帧出现前写成的一行记录出场. `decode` 财务报告和审定财务报表 `decodeAll` 这是 `Effect` 表单.

## LspStdio 语言

效果语言服务器在 stdio 上有三个陷阱 `LspStdio` 关闭每个 :

-   **`runMain` 报告 stdout 上的失败程序.** 其报告在外 `Effect.provide` 程序适用,所以 `LogToStderr` 内出不来:无法建造的地层(缺失) `HOME`将报告打印到线上. `LspStdio.launch` 提供 `LogToStderr` 对整个程序,报告stderr本身的失败, 并重新评价它标记为已报告, 保留其退出代码.
-   **出口代码是规格的.** `exit` 没有前一个 `shutdown` 1号出口 其他0号出口. `LspStdio.exitCode` 这是规则,和 `launch` 应用到 `LspSessionEnd` 您的消息循环返回 .
-   **一个干净的出入口从不单独发生.** `runMain` 结束过程本身只针对一个非零码或信号,将代码0留给事件循环排出,在stdin打开时它从未这样做——然后 `exit`stdin还开着呢. `LspStdio.teardown(process)` 明确结束进程,将SIGINT和SIGTERM的地图绘制为0而不是130.

```ts
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
import { LspStdio } from "@effected/lsp";
import { Effect } from "effect";
import { AppLayer, serve } from "./server.js";

// `serve` is your server: it runs the message loop and returns how the session ended.
NodeRuntime.runMain(LspStdio.launch(serve.pipe(Effect.provide(AppLayer))), {
  teardown: LspStdio.teardown(process),
});
```

工具箱不拥有消息循环, 因此无法看到 `shutdown` 或者说 `exit` 本身:你的循环记录它们并返回 `{ reason: "exit" | "closed", shutdownReceived }`A级 `vscode-languageserver` 连接报告通过 `onShutdown` 财务报告和审定财务报表 `onExit`。 。 。 .

`LogToStderr` 达到 Effect 的默认日志 `Logger.consolePretty`。 。 。 . `Logger.consoleJson`, (中文(简体) ), `consoleLogFmt` 财务报告和审定财务报表 `consoleStructured` 写入 `console.log` 不管怎样 —— 将一个前题包入 `Logger.withConsoleError` 相反——和 `Console.log` 仍写作出出.

## 长发

LSP 名称文档 `file:` URI,文件系统按路径排列. `LspUri` 转换双向 `node:url`因此,它也运行在一个工人:

```ts
import { LspUri } from "@effected/lsp";

const platform = process.platform === "win32" ? "win32" : "posix";

LspUri.toPath("file:///home/me/My%20Project/a.ts", { platform }); // Option.some("/home/me/My Project/a.ts")
LspUri.toPath("untitled:Untitled-1", { platform }); // Option.none()
LspUri.fromPath("C:\\Users\\me\\a.ts", { platform: "win32" }); // "file:///c:/Users/me/a.ts"
```

`toPath` 答题 `Option.none()` 而不是向一个没有路径命名的 URI 投放: 另一种方案, 一个错误的逃生, a `%2F` 一个名字,一个主机在posix. `.` 财务报告和审定财务报表 `..` 永远不要爬到根上,一个驱动器或一个UNC共享. 驱动信件会回小写, 但客户端拼写它(`C:`, (中文(简体) ), `c:` 或 VS 代码 `c%3A`),所以关键文档通过路径,而不是客户端的URI字符串.

## 长相探测器( L)`@effected/lsp/testing`(中文(简体) )

语言服务器本的装入式安装证明 `@effected/mcp-kit/testing`是因为 `McpProbe`它产生命令,运行一个编辑运行的生命周期—— `initialize`, (中文(简体) ), `initialized`, (中文(简体) ), `shutdown`, (中文(简体) ), `exit` ——然后等待服务器退出:

```ts
import * as NodeServices from "@effect/platform-node/NodeServices";
import { LspProbe } from "@effected/lsp/testing";
import { Effect } from "effect";
import { ChildProcess } from "effect/process";

const program = Effect.gen(function* () {
  const probe = yield* LspProbe.initialize(ChildProcess.make("my-lsp", ["--stdio"]));
  // A clean boot: no JSON-RPC error, exit code 0 (shutdown preceded exit), nothing on stderr.
  return probe.response.error === undefined && probe.exitCode === 0 && probe.stderr === "";
}).pipe(Effect.provide(NodeServices.layer));
```

-   `initialize` 约会 `processId` 财务报告和审定财务报表 `rootUri` `null` 和空客户端能力,除非 `LspProbeOptions` 说不然.
-   之后 Stdin 保持开放 `exit`: 服务器必须停止 `exit`因为它必须在编辑之下。 等待 stdin 关闭的服务器失败 `TimedOut`。 。 。 .
-   服务器发送的每封信都在 `messages`,顺序;它向客户发送的请求被记录下来,从未回答.
-   它从不挂起: 结束早的失败 `StreamEnded` 带有退出代码和 stderr, 非帧的字节失败 `InvalidFrame`,整个交换 运行在 `timeout` (默认为30秒). 打开它 `it.live` - 超时读取 `Clock`。 。 。 .

## 流程( E)`@effected/lsp/testing`(中文(简体) )

一个产入的服务器 一个测试驱动框架的帧——LSP双人 `@effected/mcp-kit/testing`是因为 `McpProcess`. 儿童为以下附加范围而活:

```ts
import * as NodeServices from "@effect/platform-node/NodeServices";
import { LspProcess } from "@effected/lsp/testing";
import { Effect } from "effect";
import { ChildProcess } from "effect/process";

const program = Effect.gen(function* () {
  const server = yield* LspProcess.spawn(ChildProcess.make("my-lsp", ["--stdio"]));
  yield* server.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { processId: null, rootUri: null, capabilities: {} } });
  const { response, seen } = yield* server.readUntilResponse(1);
  yield* server.send({ jsonrpc: "2.0", method: "initialized", params: {} });
  yield* server.send({ jsonrpc: "2.0", id: 2, method: "shutdown" });
  yield* server.readUntilResponse(2);
  yield* server.send({ jsonrpc: "2.0", method: "exit" });
  const exitCode = yield* server.exitCode;
  // Stdout held nothing but frames: no stray byte before, between or after them.
  const messages = yield* server.assertOnlyFrames;
  return { response, seen, exitCode, messages };
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer));
```

-   `send` 框架为 `LspFrame.encode`· ; `sendRaw` 将字节写成给定的字节,用于错误的或分框.
-   `nextMessage` 财务报告和审定财务报表 `readUntilResponse` 从不挂起: 句尾失败的 stdout `StreamEnded` (在框架内),不是框架失败的字节 `InvalidFrame`,一个不是 JSON-RPC 的身体失败 `NotJsonRpc`。 。 。 .
-   `stderrUntil(predicate, { timeout })` 等待一个报告 降落在后一滴, 被每个板块 而不是一个投票计时器唤醒 `StreamEnded` 或者说 `TimedOut` 和目前为止的钢铁。 打开它 `it.live`。 。 。 .
-   `stdoutSoFar` 财务报告和审定财务报表 `stdoutFinal` 返回生字节; `assertOnlyFrames` 等待 stdout 结束和失败 `InvalidFrame`,命名偏移字节并引用这些字节,除非每个字节都属于一个很好的框架.

## 许可证

麻省理工学院

## 常见问题

### @effected/lsp 是什么？

Effect v4 语言服务器协议基础- protocol 框架,外加一个装入的安装初始化探测器,用于语言服务器本

### 如何安装 @effected/lsp？

在项目目录运行 npm install @effected/lsp，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：effect（~4\.1\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @effected/lsp 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @effected/lsp 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @effected/lsp 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=24\.11\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @effected/lsp 可以商用吗？

@effected/lsp 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @effected/lsp 的下载量有多少？

根据 npm 官方下载统计，@effected/lsp 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,954 次，日均约 132 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @effected/lsp 还在维护吗？

最新版本 0\.9\.0 发布于 2026/11/10（2 天前）；至今共发布 12 个版本，其中过去 12 个月发布了 12 个；首次发布于 2026/10/06。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

