@epoch-agent/plugin-lsp 3.2.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +29 -44
- package/dist/index.js +43 -36
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -193,50 +193,40 @@ interface ResolveServerOptions {
|
|
|
193
193
|
declare function resolveServer(spec: ServerSpec, projectRoot: string, options?: ResolveServerOptions): ServerResolution;
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
|
-
* 一个 language server
|
|
196
|
+
* 一个 language server 连接。
|
|
197
197
|
*
|
|
198
198
|
* 协议实现**不手写**:`vscode-jsonrpc` 负责分帧和 JSON-RPC,
|
|
199
199
|
* `vscode-languageserver-protocol` 提供消息描述符和类型。真正用到的只有五条:
|
|
200
200
|
* `initialize` / `initialized` / `didOpen` / `didChange` / `publishDiagnostics`
|
|
201
201
|
* (外加 `didClose` 做逐出、`shutdown` + `exit` 做优雅退出)。
|
|
202
202
|
*
|
|
203
|
-
* 进程**一律走 infra 的 `startLongLivedProcess
|
|
204
|
-
*
|
|
205
|
-
* 我们一行清理代码都不用写。
|
|
203
|
+
* 进程**一律走 infra 的 `startLongLivedProcess`**,这个包里不长第二套进程管理 ——
|
|
204
|
+
* 顺带的好处是 `epoch` 退出时 server 被天然一并收掉,我们一行清理代码都不用写。
|
|
206
205
|
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* 连兜底表一起收。一个进程一个 runtime 的 CLI / TUI 每次 dispose 都归零,
|
|
212
|
-
* 所以和方案 60 之前逐字节相同;两个 runtime 并存时先走的那个碰不到这个池
|
|
206
|
+
* 收它的那条链子:`startLongLivedProcess` 登记进的是**进程级兜底表** —— 这个池是
|
|
207
|
+
* 模块级单例、按项目根共享,压根没有 `sessionId`,归兜底表是结论不是妥协(判据在
|
|
208
|
+
* [README](../README.md))。最后一个 runtime `dispose()` → `OwnedProcessTable.release()`
|
|
209
|
+
* 把引用计数减到 0 时连兜底表一起收;两个 runtime 并存时先走的那个碰不到这个池
|
|
213
210
|
* (否则表现是「跑了条定时任务,之后 `lsp_diagnostics` 每次都要重新冷启 tsserver」)。
|
|
214
211
|
*
|
|
215
212
|
* ## 诊断是**推**过来的,所以「什么时候算收全了」得自己判
|
|
216
213
|
*
|
|
217
|
-
* 这个协议里没有「诊断请求」这种东西(typescript-language-server 4.4 也不支持
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* 判据因此是**静默**:请求的文件都答过了,且最近一次动静距今超过 `settleMs`。
|
|
214
|
+
* 这个协议里没有「诊断请求」这种东西(typescript-language-server 4.4 也不支持 3.17
|
|
215
|
+
* 的 pull 模式 —— `initialize` 的结果里没有 `diagnosticProvider`)。server 想发就发,
|
|
216
|
+
* 而 tsserver 一个文件会**分三次**发(语法 / 语义 / 建议,各自 50ms 去抖),先到的
|
|
217
|
+
* 那一份是不全的。判据因此是**静默**:请求的文件都答过了,且最近一次动静距今超过
|
|
218
|
+
* `settleMs`。
|
|
223
219
|
*
|
|
224
220
|
* ### 还有一条更阴的:内容没变时 server 干脆不发
|
|
225
221
|
*
|
|
226
|
-
* typescript-language-server 的 `FileDiagnostics.update()
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* ```
|
|
232
|
-
*
|
|
233
|
-
* 也就是「这一类上次是空、这次还是空」就**不推送**。于是一个干净的文件被诊断
|
|
234
|
-
* 第二次时一条消息都收不到 —— 如果按「没答复 = 没结果」处理,就会把它报成
|
|
235
|
-
* 「server 没回答」,而它其实是最正常的那种情况。
|
|
222
|
+
* typescript-language-server 的 `FileDiagnostics.update()`(lib/cli.mjs)里有一句
|
|
223
|
+
* `if (this.diagnosticsPerKind.get(kind)?.length === 0 && diagnostics.length === 0) return;`
|
|
224
|
+
* —— 「这一类上次是空、这次还是空」就**不推送**。于是一个干净的文件被诊断第二次时
|
|
225
|
+
* 一条消息都收不到;按「没答复 = 没结果」处理就会把它报成「server 没回答」,而它
|
|
226
|
+
* 其实是最正常的那种情况。
|
|
236
227
|
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* 从有变没或从没变有,它就会照常推送。
|
|
228
|
+
* 所以有第二条判据:**没答复但有上一次的结果,就用上一次的**。那句 `return` 恰好只在
|
|
229
|
+
* 「什么都没变、也没什么可报」时生效;一旦某一类从有变没或从没变有,它就会照常推送。
|
|
240
230
|
*/
|
|
241
231
|
|
|
242
232
|
/** 一次批量诊断的输入 */
|
|
@@ -315,14 +305,13 @@ declare class LspClient implements DiagnosticsClient {
|
|
|
315
305
|
private stderr;
|
|
316
306
|
private constructor();
|
|
317
307
|
get pid(): number;
|
|
318
|
-
/**
|
|
308
|
+
/** 还能用吗。池按这个决定要不要重启 */
|
|
319
309
|
get alive(): boolean;
|
|
320
310
|
/**
|
|
321
311
|
* 起进程 + `initialize` + `initialized`。
|
|
322
312
|
*
|
|
323
|
-
* 起不来 / 初始化超时都**返回 `null` 而不抛** ——
|
|
324
|
-
*
|
|
325
|
-
* 调用失败,而那正是这条验收要避免的。
|
|
313
|
+
* 起不来 / 初始化超时都**返回 `null` 而不抛** —— 调用方据此把这个语言标记不可用,
|
|
314
|
+
* 整轮照常出结果。抛出去的话一个慢 server 就能让整次工具调用失败。
|
|
326
315
|
*/
|
|
327
316
|
static start(options: StartClientOptions): Promise<LspClient | null>;
|
|
328
317
|
/** 订阅推送 + 兜住 server 反过来发的那几种请求 */
|
|
@@ -333,7 +322,7 @@ declare class LspClient implements DiagnosticsClient {
|
|
|
333
322
|
/**
|
|
334
323
|
* 打开 / 更新这批文件,等到静默,交出诊断。
|
|
335
324
|
*
|
|
336
|
-
* @throws {LspServerDownError}
|
|
325
|
+
* @throws {LspServerDownError} 进程中途没了
|
|
337
326
|
*/
|
|
338
327
|
diagnose(documents: DocumentInput[], wait: WaitOptions): Promise<DiagnoseBatch>;
|
|
339
328
|
/** 没打开过就 `didOpen`,打开过就 `didChange`(全量) */
|
|
@@ -345,21 +334,17 @@ declare class LspClient implements DiagnosticsClient {
|
|
|
345
334
|
*
|
|
346
335
|
* 先按协议 `shutdown` + `exit`,给它清临时文件的机会;超预算就直接杀树。
|
|
347
336
|
* **杀树那一步不能省** —— `typescript-language-server` 自己还 fork 了一个
|
|
348
|
-
* `tsserver.js
|
|
337
|
+
* `tsserver.js`,只杀父进程会留下孤儿。
|
|
349
338
|
*
|
|
350
339
|
* ## ⚠️ 三步的**顺序**是判据:拍快照 → 优雅关 → 清扫快照
|
|
351
340
|
*
|
|
352
|
-
* 这里原来只有两步(优雅关 → `killTrackedProcess`),而那是**漏的**:
|
|
353
341
|
* `killTrackedProcess` 底下是 `killProcessTree`,靠的是**现场遍历**
|
|
354
|
-
* (`pgrep -P` / `taskkill /t`)。等我们优雅关完,直接子进程已经退了 ——
|
|
355
|
-
*
|
|
356
|
-
*
|
|
342
|
+
* (`pgrep -P` / `taskkill /t`)。等我们优雅关完,直接子进程已经退了 —— 树的根
|
|
343
|
+
* 没了,孙进程的 PPID 指向一个死 pid,遍历再也找不到它们:`tsserver` 那一层在
|
|
344
|
+
* POSIX 上被 init 收养、在 Windows 上直接常驻到关机。所以快照必须在**动手之前**拍。
|
|
357
345
|
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
* 我们这边验收 #7 一直挂着「双平台手验」没人做,于是漏了一年半。
|
|
361
|
-
* 2026-08-12 补的 [orphan-reap.test.ts](../__tests__/orphan-reap.test.ts)
|
|
362
|
-
* 把这条钉死了 —— 把下面的快照挪到 `killTrackedProcess` 之后,它当场红。
|
|
346
|
+
* `orphan-reap.test.ts` 把这条钉死了 —— 把下面的快照挪到 `killTrackedProcess`
|
|
347
|
+
* 之后,它当场红。
|
|
363
348
|
*/
|
|
364
349
|
dispose(): Promise<void>;
|
|
365
350
|
}
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var MAX_OPEN_DOCUMENTS = 64;
|
|
|
34
34
|
var POLL_STEP_MS = 25;
|
|
35
35
|
var LspServerDownError = class extends Error {
|
|
36
36
|
constructor(detail) {
|
|
37
|
-
super(`language server
|
|
37
|
+
super(`language server exited: ${detail}`);
|
|
38
38
|
this.detail = detail;
|
|
39
39
|
this.name = "LspServerDownError";
|
|
40
40
|
}
|
|
@@ -137,8 +137,8 @@ var LspClient = class _LspClient {
|
|
|
137
137
|
this.connection.onRequest(RegistrationRequest.type, () => void 0);
|
|
138
138
|
this.connection.onRequest(UnregistrationRequest.type, () => void 0);
|
|
139
139
|
this.connection.onRequest(WorkDoneProgressCreateRequest.type, () => void 0);
|
|
140
|
-
this.connection.onError(() => this.markDead("JSON-RPC
|
|
141
|
-
this.connection.onClose(() => this.markDead("JSON-RPC
|
|
140
|
+
this.connection.onError(() => this.markDead("JSON-RPC connection error"));
|
|
141
|
+
this.connection.onClose(() => this.markDead("JSON-RPC connection closed"));
|
|
142
142
|
}
|
|
143
143
|
appendStderr(chunk) {
|
|
144
144
|
this.stderr = (this.stderr + chunk).slice(-STDERR_KEEP);
|
|
@@ -146,7 +146,7 @@ var LspClient = class _LspClient {
|
|
|
146
146
|
markDead(detail, onCrash) {
|
|
147
147
|
if (this.dead) return;
|
|
148
148
|
const tail = this.stderr.trim();
|
|
149
|
-
this.dead = tail ? `${detail}
|
|
149
|
+
this.dead = tail ? `${detail}; stderr: ${tail.slice(-500)}` : detail;
|
|
150
150
|
if (!this.disposing) onCrash?.(this.dead);
|
|
151
151
|
}
|
|
152
152
|
async initialize(projectRoot) {
|
|
@@ -258,7 +258,7 @@ var LspClient = class _LspClient {
|
|
|
258
258
|
this.connection.dispose();
|
|
259
259
|
} catch {
|
|
260
260
|
}
|
|
261
|
-
this.dead ??= "
|
|
261
|
+
this.dead ??= "disposed";
|
|
262
262
|
await killTrackedProcess(this.pidValue);
|
|
263
263
|
if (tree.length > 0) await killStampedPids(tree, { escalate: true });
|
|
264
264
|
}
|
|
@@ -322,7 +322,7 @@ var TYPESCRIPT = {
|
|
|
322
322
|
pkg: "typescript-language-server",
|
|
323
323
|
bin: "typescript-language-server",
|
|
324
324
|
args: ["--stdio"],
|
|
325
|
-
install: "npm i -D typescript-language-server typescript
|
|
325
|
+
install: "npm i -D typescript-language-server typescript (or install globally with npm i -g)",
|
|
326
326
|
initTimeoutMs: 3e4,
|
|
327
327
|
initializationOptions: (projectRoot) => {
|
|
328
328
|
const path = tsserverPath(projectRoot);
|
|
@@ -394,7 +394,7 @@ async function classify(paths, workDir, outcome) {
|
|
|
394
394
|
const absPath = isAbsolute(raw) ? resolve2(raw) : resolve2(root, raw);
|
|
395
395
|
const rel = relative(root, absPath);
|
|
396
396
|
if (rel !== "" && (rel.startsWith("..") || isAbsolute(rel))) {
|
|
397
|
-
outcome.rejected.push({ path: raw, reason:
|
|
397
|
+
outcome.rejected.push({ path: raw, reason: `outside the workspace ${root}` });
|
|
398
398
|
continue;
|
|
399
399
|
}
|
|
400
400
|
const key = uriKey(`file://${absPath.split(sep).join("/")}`);
|
|
@@ -404,11 +404,11 @@ async function classify(paths, workDir, outcome) {
|
|
|
404
404
|
try {
|
|
405
405
|
const info = await stat(absPath);
|
|
406
406
|
if (!info.isFile()) {
|
|
407
|
-
outcome.rejected.push({ path: display, reason: "
|
|
407
|
+
outcome.rejected.push({ path: display, reason: "not a file" });
|
|
408
408
|
continue;
|
|
409
409
|
}
|
|
410
410
|
} catch {
|
|
411
|
-
outcome.rejected.push({ path: display, reason: "
|
|
411
|
+
outcome.rejected.push({ path: display, reason: "file does not exist" });
|
|
412
412
|
continue;
|
|
413
413
|
}
|
|
414
414
|
const match = serverForExtension(extname(absPath));
|
|
@@ -452,7 +452,7 @@ async function runGroup(spec, files, input, outcome) {
|
|
|
452
452
|
} catch (err) {
|
|
453
453
|
outcome.rejected.push({
|
|
454
454
|
path: file.display,
|
|
455
|
-
reason:
|
|
455
|
+
reason: `cannot read it (${err instanceof Error ? err.message : String(err)})`
|
|
456
456
|
});
|
|
457
457
|
continue;
|
|
458
458
|
}
|
|
@@ -464,7 +464,7 @@ async function runGroup(spec, files, input, outcome) {
|
|
|
464
464
|
try {
|
|
465
465
|
batch = await acquired.client.diagnose(documents, input.wait ?? DEFAULT_WAIT);
|
|
466
466
|
} catch (err) {
|
|
467
|
-
const reason = err instanceof LspServerDownError ? err.message :
|
|
467
|
+
const reason = err instanceof LspServerDownError ? err.message : `diagnostics failed (${String(err)})`;
|
|
468
468
|
outcome.skipped.push(skip(spec, reason, files));
|
|
469
469
|
return;
|
|
470
470
|
}
|
|
@@ -477,7 +477,11 @@ async function runGroup(spec, files, input, outcome) {
|
|
|
477
477
|
if (batch.pending.length > 0) {
|
|
478
478
|
const stuck = batch.pending.map((key) => byKey.get(key)).filter((f) => !!f);
|
|
479
479
|
outcome.skipped.push(
|
|
480
|
-
skip(
|
|
480
|
+
skip(
|
|
481
|
+
spec,
|
|
482
|
+
`the server gave no result within ${(input.wait ?? DEFAULT_WAIT).timeoutMs}ms`,
|
|
483
|
+
stuck
|
|
484
|
+
)
|
|
481
485
|
);
|
|
482
486
|
}
|
|
483
487
|
}
|
|
@@ -491,12 +495,12 @@ async function diagnosePaths(input) {
|
|
|
491
495
|
};
|
|
492
496
|
const paths = input.paths.slice(0, MAX_FILES_PER_CALL);
|
|
493
497
|
for (const extra of input.paths.slice(MAX_FILES_PER_CALL)) {
|
|
494
|
-
outcome.rejected.push({ path: extra, reason:
|
|
498
|
+
outcome.rejected.push({ path: extra, reason: `at most ${MAX_FILES_PER_CALL} files per call` });
|
|
495
499
|
}
|
|
496
500
|
const candidates = await classify(paths, resolve2(input.workDir), outcome);
|
|
497
501
|
for (const group of groupBySpec(candidates).values()) {
|
|
498
502
|
if (input.signal?.aborted) {
|
|
499
|
-
outcome.skipped.push(skip(group.spec, "
|
|
503
|
+
outcome.skipped.push(skip(group.spec, "cancelled", group.files));
|
|
500
504
|
continue;
|
|
501
505
|
}
|
|
502
506
|
await runGroup(group.spec, group.files, input, outcome);
|
|
@@ -533,7 +537,7 @@ function renderCounts(items) {
|
|
|
533
537
|
}
|
|
534
538
|
function renderFiles(files) {
|
|
535
539
|
if (files.length <= MAX_FILE_NAMES) return files.join(", ");
|
|
536
|
-
return `${files.slice(0, MAX_FILE_NAMES).join(", ")} \
|
|
540
|
+
return `${files.slice(0, MAX_FILE_NAMES).join(", ")} \u2026 (${files.length} total)`;
|
|
537
541
|
}
|
|
538
542
|
function pickItems(items) {
|
|
539
543
|
if (items.length <= MAX_ITEMS) return { shown: items, dropped: 0 };
|
|
@@ -551,29 +555,29 @@ function formatOutcome(outcome) {
|
|
|
551
555
|
const { checked, diagnostics, skipped, unsupported, rejected } = outcome;
|
|
552
556
|
if (diagnostics.length === 0) {
|
|
553
557
|
lines.push(
|
|
554
|
-
checked.length > 0 ?
|
|
558
|
+
checked.length > 0 ? `No problems found \xB7 checked ${checked.length} file(s): ${renderFiles(checked)}` : "No files were checked"
|
|
555
559
|
);
|
|
556
560
|
} else {
|
|
557
561
|
const { shown, dropped } = pickItems(diagnostics);
|
|
558
562
|
lines.push(
|
|
559
|
-
`${diagnostics.length}
|
|
563
|
+
`${diagnostics.length} diagnostic(s) (${renderCounts(diagnostics)}) \xB7 checked ${checked.length} file(s)`,
|
|
560
564
|
"",
|
|
561
565
|
...shown.map(renderItem)
|
|
562
566
|
);
|
|
563
567
|
if (dropped > 0) {
|
|
564
|
-
lines.push("",
|
|
568
|
+
lines.push("", `(${dropped} more not listed; errors were kept first)`);
|
|
565
569
|
}
|
|
566
570
|
}
|
|
567
571
|
for (const skip2 of skipped) {
|
|
568
|
-
lines.push("",
|
|
569
|
-
if (skip2.install) lines.push(`
|
|
570
|
-
if (skip2.files.length > 0) lines.push(`
|
|
572
|
+
lines.push("", `Skipped ${skip2.label}: ${skip2.reason}`);
|
|
573
|
+
if (skip2.install) lines.push(` install: ${skip2.install}`);
|
|
574
|
+
if (skip2.files.length > 0) lines.push(` not checked: ${renderFiles(skip2.files)}`);
|
|
571
575
|
}
|
|
572
576
|
if (unsupported.length > 0) {
|
|
573
|
-
lines.push("",
|
|
577
|
+
lines.push("", `No matching language server; not checked: ${renderFiles(unsupported)}`);
|
|
574
578
|
}
|
|
575
579
|
for (const bad of rejected) {
|
|
576
|
-
lines.push("",
|
|
580
|
+
lines.push("", `Cannot check ${bad.path}: ${bad.reason}`);
|
|
577
581
|
}
|
|
578
582
|
return lines.join("\n");
|
|
579
583
|
}
|
|
@@ -664,7 +668,7 @@ function resolveServer(spec, projectRoot, options = {}) {
|
|
|
664
668
|
if (launch) return { available: true, launch };
|
|
665
669
|
return {
|
|
666
670
|
available: false,
|
|
667
|
-
reason:
|
|
671
|
+
reason: `could not find ${spec.bin} (not in the project's node_modules, nor on PATH)`,
|
|
668
672
|
install: spec.install
|
|
669
673
|
};
|
|
670
674
|
}
|
|
@@ -702,13 +706,13 @@ var LspServerPool = class {
|
|
|
702
706
|
return { ok: true, client: existing.client };
|
|
703
707
|
}
|
|
704
708
|
this.entries.delete(key);
|
|
705
|
-
this.noteFailure(key, "language server
|
|
709
|
+
this.noteFailure(key, "language server process has exited");
|
|
706
710
|
}
|
|
707
711
|
const failed = this.failures.get(key);
|
|
708
712
|
if (failed && failed.count >= MAX_FAILURES) {
|
|
709
713
|
return {
|
|
710
714
|
ok: false,
|
|
711
|
-
reason: `${failed.detail}
|
|
715
|
+
reason: `${failed.detail} (failed ${failed.count} times in a row; not restarting in this session)`
|
|
712
716
|
};
|
|
713
717
|
}
|
|
714
718
|
const inflight = this.starting.get(key);
|
|
@@ -732,15 +736,18 @@ var LspServerPool = class {
|
|
|
732
736
|
projectRoot,
|
|
733
737
|
onCrash: (detail) => {
|
|
734
738
|
this.entries.delete(key);
|
|
735
|
-
this.noteFailure(key, `language server
|
|
739
|
+
this.noteFailure(key, `language server crashed (${detail})`);
|
|
736
740
|
}
|
|
737
741
|
});
|
|
738
742
|
if (!client) {
|
|
739
|
-
this.noteFailure(
|
|
743
|
+
this.noteFailure(
|
|
744
|
+
key,
|
|
745
|
+
`language server failed to start or initialize timed out (>${spec.initTimeoutMs}ms)`
|
|
746
|
+
);
|
|
740
747
|
const now = this.failures.get(key);
|
|
741
748
|
return {
|
|
742
749
|
ok: false,
|
|
743
|
-
reason: now && now.count >= MAX_FAILURES ? `${now.detail}
|
|
750
|
+
reason: now && now.count >= MAX_FAILURES ? `${now.detail} (not restarting in this session)` : now?.detail ?? "failed to start"
|
|
744
751
|
};
|
|
745
752
|
}
|
|
746
753
|
this.entries.set(key, { client, lastUsedAt: this.now() });
|
|
@@ -814,18 +821,18 @@ function fail(code, message, suggestion, started) {
|
|
|
814
821
|
var lspPlugin = {
|
|
815
822
|
name: "@epoch-agent/plugin-lsp",
|
|
816
823
|
version: "0.0.0",
|
|
817
|
-
description: "
|
|
824
|
+
description: "Language-server diagnostics \u2014 type and syntax errors from the project's own language server",
|
|
818
825
|
tools: [
|
|
819
826
|
{
|
|
820
827
|
name: "lsp_diagnostics",
|
|
821
|
-
description:
|
|
828
|
+
description: `Check files with the project's own language server and return type errors, syntax errors and unused-variable warnings. Supported extensions: ${supportedExtensions().join(" ")}. Call it once after changing code and before saying the work is finished, listing the source files you created or modified. It is much faster than running tsc through the shell because the language server is already resident. It only does single-file diagnostics, which is not the same as a full build: problems from build scripts, bundler config or cross-package type resolution are invisible to it. When no language server is installed it reports "skipped" and prints the install command instead of failing.`,
|
|
822
829
|
parameters: {
|
|
823
830
|
type: "object",
|
|
824
831
|
properties: {
|
|
825
832
|
paths: {
|
|
826
833
|
type: "array",
|
|
827
834
|
items: { type: "string" },
|
|
828
|
-
description: '
|
|
835
|
+
description: 'File paths to check (relative to the working directory, or absolute), e.g. ["src/a.ts", "src/b.tsx"].'
|
|
829
836
|
}
|
|
830
837
|
},
|
|
831
838
|
required: ["paths"]
|
|
@@ -839,8 +846,8 @@ var lspPlugin = {
|
|
|
839
846
|
if (!paths) {
|
|
840
847
|
return fail(
|
|
841
848
|
ERR_BAD_PATHS,
|
|
842
|
-
"paths
|
|
843
|
-
'
|
|
849
|
+
"paths must be a non-empty array of file paths",
|
|
850
|
+
'List the source files you changed in this turn, e.g. {"paths": ["src/a.ts"]}',
|
|
844
851
|
started
|
|
845
852
|
);
|
|
846
853
|
}
|
|
@@ -855,8 +862,8 @@ var lspPlugin = {
|
|
|
855
862
|
} catch (err) {
|
|
856
863
|
return fail(
|
|
857
864
|
ERR_UNEXPECTED,
|
|
858
|
-
|
|
859
|
-
"
|
|
865
|
+
`diagnostics failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
866
|
+
"You can keep going, or run the project's own type-check command through terminal instead",
|
|
860
867
|
started
|
|
861
868
|
);
|
|
862
869
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epoch-agent/plugin-lsp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "LSP 诊断插件 — 探测项目自带的 language server,按文件取语义诊断",
|
|
6
6
|
"repository": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"vscode-jsonrpc": "^9.0.1",
|
|
26
26
|
"vscode-languageserver-protocol": "^3.17.5",
|
|
27
|
-
"@epoch-agent/infra": "
|
|
28
|
-
"@epoch-agent/protocol": "
|
|
27
|
+
"@epoch-agent/infra": "4.1.0",
|
|
28
|
+
"@epoch-agent/protocol": "4.1.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^26.1.2",
|