berry-agent 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/.api-emit.stamp +1 -0
- package/dist/.build-meta.json +6 -0
- package/dist/agent/events.js +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/loop.js +139 -0
- package/dist/agent/queue.js +119 -0
- package/dist/agent/stream.js +62 -0
- package/dist/agent/tools-batch.js +221 -0
- package/dist/agent/types.js +8 -0
- package/dist/api/berry-agent-llm.d.ts +18 -0
- package/dist/api/berry-agent.d.ts +9 -0
- package/dist/api/surface.json +1632 -0
- package/dist/api/tsconfig.paths.json +12 -0
- package/dist/api/typebox-compile.d.ts +2 -0
- package/dist/api/typebox-value.d.ts +2 -0
- package/dist/api/typebox.d.ts +2 -0
- package/dist/browser/cdp.js +256 -0
- package/dist/browser/codes.js +31 -0
- package/dist/browser/discover.js +107 -0
- package/dist/browser/engine.js +169 -0
- package/dist/browser/index.js +17 -0
- package/dist/browser/install.js +342 -0
- package/dist/browser/page.js +321 -0
- package/dist/browser/service.js +158 -0
- package/dist/browser/tools.js +198 -0
- package/dist/browser/types.js +81 -0
- package/dist/channels/ask-queue.js +82 -0
- package/dist/channels/commands.js +129 -0
- package/dist/channels/engine/cell.js +143 -0
- package/dist/channels/engine/diff.js +143 -0
- package/dist/channels/engine/engine.js +416 -0
- package/dist/channels/engine/index.js +8 -0
- package/dist/channels/engine/input-keys.js +86 -0
- package/dist/channels/engine/input.js +596 -0
- package/dist/channels/engine/memory-io.js +71 -0
- package/dist/channels/engine/process-io.js +38 -0
- package/dist/channels/engine/types.js +17 -0
- package/dist/channels/engine/width.js +122 -0
- package/dist/channels/index.js +15 -0
- package/dist/channels/registry.js +56 -0
- package/dist/channels/sdk/admit.js +29 -0
- package/dist/channels/sdk/backend.js +102 -0
- package/dist/channels/sdk/cursor.js +56 -0
- package/dist/channels/sdk/index.js +20 -0
- package/dist/channels/sdk/jsonl.js +208 -0
- package/dist/channels/sdk/protocol.js +24 -0
- package/dist/channels/sdk/schema.js +91 -0
- package/dist/channels/sdk/wire-core.js +446 -0
- package/dist/channels/service.js +169 -0
- package/dist/channels/tui/autocomplete/autocomplete.js +42 -0
- package/dist/channels/tui/autocomplete/file-mentions.js +106 -0
- package/dist/channels/tui/autocomplete/popup.js +148 -0
- package/dist/channels/tui/autocomplete/provider.js +7 -0
- package/dist/channels/tui/autocomplete/token.js +68 -0
- package/dist/channels/tui/backend/ansi-rows.js +211 -0
- package/dist/channels/tui/backend/main-screen.js +207 -0
- package/dist/channels/tui/backend/osc.js +91 -0
- package/dist/channels/tui/backend/transcript.js +230 -0
- package/dist/channels/tui/backend/tui-backend.js +915 -0
- package/dist/channels/tui/editor/editor-model.js +543 -0
- package/dist/channels/tui/editor/editor-view.js +140 -0
- package/dist/channels/tui/editor/editor.js +275 -0
- package/dist/channels/tui/editor/undo-stack.js +35 -0
- package/dist/channels/tui/editor/visual-lines.js +126 -0
- package/dist/channels/tui/editor/word-nav.js +106 -0
- package/dist/channels/tui/history/history-viewer.js +403 -0
- package/dist/channels/tui/index.js +3 -0
- package/dist/channels/tui/layout.js +167 -0
- package/dist/channels/tui/markdown/blocks.js +111 -0
- package/dist/channels/tui/markdown/inline.js +75 -0
- package/dist/channels/tui/markdown/markdown.js +182 -0
- package/dist/channels/tui/memory/memory-viewer.js +540 -0
- package/dist/channels/tui/overlay/alt-screen.js +105 -0
- package/dist/channels/tui/overlay/overlay.js +57 -0
- package/dist/channels/tui/overlay/select-confirm.js +156 -0
- package/dist/channels/tui/panels/todo-panel.js +54 -0
- package/dist/channels/tui/panels/tool-progress-panel.js +93 -0
- package/dist/channels/tui/scroll/scroll-view.js +254 -0
- package/dist/channels/tui/status/status-line.js +76 -0
- package/dist/channels/tui/text.js +38 -0
- package/dist/channels/tui/theme.js +41 -0
- package/dist/channels/types.js +11 -0
- package/dist/channels/ui-core.js +209 -0
- package/dist/checkpoint/capture.js +45 -0
- package/dist/checkpoint/codes.js +33 -0
- package/dist/checkpoint/command.js +82 -0
- package/dist/checkpoint/gate.js +48 -0
- package/dist/checkpoint/index.js +20 -0
- package/dist/checkpoint/restore.js +172 -0
- package/dist/checkpoint/store.js +247 -0
- package/dist/checkpoint/types.js +4 -0
- package/dist/checkpoint/walk.js +146 -0
- package/dist/compaction/ccr-tools.js +112 -0
- package/dist/compaction/ccr.js +84 -0
- package/dist/compaction/codes.js +21 -0
- package/dist/compaction/index.js +18 -0
- package/dist/compaction/policy.js +200 -0
- package/dist/compaction/service.js +422 -0
- package/dist/compaction/slots.js +121 -0
- package/dist/compaction/types.js +10 -0
- package/dist/context/codes.js +40 -0
- package/dist/context/events.js +160 -0
- package/dist/context/index.js +13 -0
- package/dist/context/logger.js +136 -0
- package/dist/context/scope.js +182 -0
- package/dist/context/workspace.js +104 -0
- package/dist/contracts/agent-events.d.ts +73 -0
- package/dist/contracts/agent-events.js +16 -0
- package/dist/contracts/api.d.ts +249 -0
- package/dist/contracts/api.js +299 -0
- package/dist/contracts/approval.d.ts +37 -0
- package/dist/contracts/approval.js +9 -0
- package/dist/contracts/env-ref.d.ts +41 -0
- package/dist/contracts/env-ref.js +32 -0
- package/dist/contracts/errors.d.ts +56 -0
- package/dist/contracts/errors.js +266 -0
- package/dist/contracts/events.d.ts +70 -0
- package/dist/contracts/events.js +329 -0
- package/dist/contracts/index.d.ts +32 -0
- package/dist/contracts/index.js +26 -0
- package/dist/contracts/llm.d.ts +275 -0
- package/dist/contracts/llm.js +12 -0
- package/dist/contracts/messages.d.ts +63 -0
- package/dist/contracts/messages.js +65 -0
- package/dist/contracts/redact.d.ts +46 -0
- package/dist/contracts/redact.js +223 -0
- package/dist/contracts/tools.d.ts +197 -0
- package/dist/contracts/tools.js +33 -0
- package/dist/contracts/types.d.ts +302 -0
- package/dist/contracts/types.js +50 -0
- package/dist/contracts/ui.d.ts +122 -0
- package/dist/contracts/ui.js +15 -0
- package/dist/conversation/agent-service.js +61 -0
- package/dist/conversation/approval-wiring.js +82 -0
- package/dist/conversation/backoff.js +38 -0
- package/dist/conversation/codes.js +47 -0
- package/dist/conversation/control-tools.js +102 -0
- package/dist/conversation/control.js +210 -0
- package/dist/conversation/driver.js +922 -0
- package/dist/conversation/index.js +12 -0
- package/dist/conversation/model-visible.js +169 -0
- package/dist/conversation/open-tools.js +126 -0
- package/dist/conversation/reseed.js +132 -0
- package/dist/conversation/sessions.js +215 -0
- package/dist/conversation/todo.js +203 -0
- package/dist/conversation/types.js +35 -0
- package/dist/conversation/wiring.js +204 -0
- package/dist/credentials/codes.js +59 -0
- package/dist/credentials/commands.js +186 -0
- package/dist/credentials/env-ref.js +34 -0
- package/dist/credentials/index.js +28 -0
- package/dist/credentials/migration.js +18 -0
- package/dist/credentials/oauth.js +266 -0
- package/dist/credentials/refresh.js +152 -0
- package/dist/credentials/secrets.js +118 -0
- package/dist/credentials/types.js +30 -0
- package/dist/exec/bash.js +279 -0
- package/dist/exec/codes.js +37 -0
- package/dist/exec/env.js +99 -0
- package/dist/exec/environment.js +39 -0
- package/dist/exec/git-guard.js +623 -0
- package/dist/exec/index.js +24 -0
- package/dist/exec/registry.js +120 -0
- package/dist/exec/spawn.js +281 -0
- package/dist/exec/tail.js +77 -0
- package/dist/exec/types.js +5 -0
- package/dist/goal/codes.js +33 -0
- package/dist/goal/command.js +175 -0
- package/dist/goal/fold.js +121 -0
- package/dist/goal/gates.js +122 -0
- package/dist/goal/index.js +22 -0
- package/dist/goal/migration.js +48 -0
- package/dist/goal/service.js +501 -0
- package/dist/goal/todo-tool.js +174 -0
- package/dist/goal/types.js +1 -0
- package/dist/goal/update-tool.js +46 -0
- package/dist/host/approval-cmd.js +276 -0
- package/dist/host/assembly.js +1146 -0
- package/dist/host/boot-failures.js +104 -0
- package/dist/host/budget-advisory.js +74 -0
- package/dist/host/budget-broadcast.js +50 -0
- package/dist/host/builtins.js +54 -0
- package/dist/host/cli.js +544 -0
- package/dist/host/codes.js +120 -0
- package/dist/host/config-schema.js +195 -0
- package/dist/host/conversation-stack.js +654 -0
- package/dist/host/core-plugins.js +1685 -0
- package/dist/host/credentials-cmd.js +42 -0
- package/dist/host/disclosure.js +30 -0
- package/dist/host/dispatch.js +105 -0
- package/dist/host/doors-cmd.js +154 -0
- package/dist/host/dump-config.js +44 -0
- package/dist/host/hook-dispatch-guard.js +27 -0
- package/dist/host/import-gate.js +153 -0
- package/dist/host/index.js +54 -0
- package/dist/host/issue-session.js +241 -0
- package/dist/host/loader.js +372 -0
- package/dist/host/main.js +161 -0
- package/dist/host/manifest.js +381 -0
- package/dist/host/mcp-entry.js +53 -0
- package/dist/host/plugin-boot.js +952 -0
- package/dist/host/plugin-context.js +672 -0
- package/dist/host/plugin-install.js +480 -0
- package/dist/host/plugin-reload.js +124 -0
- package/dist/host/plugin-store.js +462 -0
- package/dist/host/plugin-tools.js +359 -0
- package/dist/host/plugin-uninstall.js +257 -0
- package/dist/host/plugins-cmd.js +302 -0
- package/dist/host/plugins-command.js +130 -0
- package/dist/host/plugins-config.js +195 -0
- package/dist/host/prompt-sections.js +133 -0
- package/dist/host/run-entry.js +544 -0
- package/dist/host/runtime.js +209 -0
- package/dist/host/scheduler-tick.js +294 -0
- package/dist/host/serve-daemon.js +501 -0
- package/dist/host/serve-entry.js +279 -0
- package/dist/host/session-anchor.js +41 -0
- package/dist/host/sessions-cmd.js +219 -0
- package/dist/host/sessions-face.js +47 -0
- package/dist/host/settings-store.js +112 -0
- package/dist/host/signals.js +69 -0
- package/dist/host/single-instance.js +105 -0
- package/dist/host/subagent-factory.js +291 -0
- package/dist/host/testkit/harness.js +283 -0
- package/dist/host/testkit/index.js +14 -0
- package/dist/host/testkit/matrix.js +302 -0
- package/dist/host/tool-policy-store.js +177 -0
- package/dist/host/triggers.js +212 -0
- package/dist/host/tui-entry.js +216 -0
- package/dist/host/webui-bridge.js +165 -0
- package/dist/issue/codes.js +38 -0
- package/dist/issue/filter.js +146 -0
- package/dist/issue/github.js +116 -0
- package/dist/issue/index.js +17 -0
- package/dist/issue/mount.js +70 -0
- package/dist/issue/poll.js +58 -0
- package/dist/issue/service.js +341 -0
- package/dist/issue/tools.js +70 -0
- package/dist/issue/types.js +34 -0
- package/dist/issue/webhook.js +126 -0
- package/dist/llm/codes.js +77 -0
- package/dist/llm/complete.js +196 -0
- package/dist/llm/events.js +15 -0
- package/dist/llm/index.js +24 -0
- package/dist/llm/inflight.js +65 -0
- package/dist/llm/model-id.js +58 -0
- package/dist/llm/provider-face.d.ts +32 -0
- package/dist/llm/provider-face.js +34 -0
- package/dist/llm/recovery.js +146 -0
- package/dist/llm/runtime.js +46 -0
- package/dist/llm/stream-fn.js +147 -0
- package/dist/lsp/codes.js +31 -0
- package/dist/lsp/connection.js +147 -0
- package/dist/lsp/frame.js +110 -0
- package/dist/lsp/index.js +16 -0
- package/dist/lsp/inject.js +58 -0
- package/dist/lsp/instance.js +264 -0
- package/dist/lsp/service.js +522 -0
- package/dist/lsp/tools.js +53 -0
- package/dist/lsp/types.js +201 -0
- package/dist/mcp/bridge.js +222 -0
- package/dist/mcp/codes.js +21 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/jsonrpc.js +230 -0
- package/dist/mcp/service.js +125 -0
- package/dist/mcp/tools.js +145 -0
- package/dist/mcp/types.js +108 -0
- package/dist/memory/cite.js +131 -0
- package/dist/memory/codes.js +50 -0
- package/dist/memory/command.js +71 -0
- package/dist/memory/consolidate.js +219 -0
- package/dist/memory/cycle.js +109 -0
- package/dist/memory/dao.js +878 -0
- package/dist/memory/diff.js +238 -0
- package/dist/memory/extract.js +181 -0
- package/dist/memory/fts.js +58 -0
- package/dist/memory/index.js +42 -0
- package/dist/memory/inject.js +354 -0
- package/dist/memory/merge.js +178 -0
- package/dist/memory/migration.js +132 -0
- package/dist/memory/pollution.js +59 -0
- package/dist/memory/port.js +385 -0
- package/dist/memory/review.js +201 -0
- package/dist/memory/scan.js +89 -0
- package/dist/memory/tools.js +508 -0
- package/dist/memory/types.js +140 -0
- package/dist/obs/codes.js +38 -0
- package/dist/obs/db.js +115 -0
- package/dist/obs/index.js +20 -0
- package/dist/obs/rollup.js +61 -0
- package/dist/obs/service.js +363 -0
- package/dist/obs/session-tools.js +282 -0
- package/dist/obs/session-view.js +225 -0
- package/dist/obs/tool.js +97 -0
- package/dist/obs/types.js +1 -0
- package/dist/persist/audit.js +63 -0
- package/dist/persist/aux.js +39 -0
- package/dist/persist/codes.js +35 -0
- package/dist/persist/index.js +30 -0
- package/dist/persist/load-history.js +50 -0
- package/dist/persist/migrations.js +37 -0
- package/dist/persist/paths.js +108 -0
- package/dist/persist/persistence.js +229 -0
- package/dist/persist/schema.js +99 -0
- package/dist/persist/secret-box.js +95 -0
- package/dist/persist/store.js +706 -0
- package/dist/persist/write-behind.js +238 -0
- package/dist/safety/approval.js +171 -0
- package/dist/safety/bwrap.js +123 -0
- package/dist/safety/codes.js +57 -0
- package/dist/safety/danger.js +505 -0
- package/dist/safety/gate.js +226 -0
- package/dist/safety/index.js +24 -0
- package/dist/safety/presets.js +73 -0
- package/dist/safety/roots.js +139 -0
- package/dist/safety/sandbox.js +214 -0
- package/dist/safety/seatbelt.js +88 -0
- package/dist/safety/sensitive.js +34 -0
- package/dist/safety/tool-policy.js +203 -0
- package/dist/safety/types.js +13 -0
- package/dist/scheduler/codes.js +54 -0
- package/dist/scheduler/cron-backend.js +135 -0
- package/dist/scheduler/engine.js +280 -0
- package/dist/scheduler/gates.js +60 -0
- package/dist/scheduler/index.js +25 -0
- package/dist/scheduler/migration.js +22 -0
- package/dist/scheduler/runner.js +171 -0
- package/dist/scheduler/schedule.js +193 -0
- package/dist/scheduler/service.js +283 -0
- package/dist/scheduler/tick.js +139 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/sdk/http.js +865 -0
- package/dist/sdk/index.js +22 -0
- package/dist/sdk/mcp.js +289 -0
- package/dist/sdk/plugin-route-registry.js +126 -0
- package/dist/sdk/plugin-routes.js +149 -0
- package/dist/sdk/security.js +116 -0
- package/dist/sdk/types.js +32 -0
- package/dist/session/budget.js +159 -0
- package/dist/session/codes.js +40 -0
- package/dist/session/derive.js +180 -0
- package/dist/session/event-data.js +1 -0
- package/dist/session/fork.js +72 -0
- package/dist/session/import-gates.js +148 -0
- package/dist/session/index.js +18 -0
- package/dist/session/recover.js +103 -0
- package/dist/session/session.js +279 -0
- package/dist/session/snapshot.js +107 -0
- package/dist/skills/agents.js +242 -0
- package/dist/skills/codes.js +51 -0
- package/dist/skills/discovery.js +266 -0
- package/dist/skills/frontmatter.js +215 -0
- package/dist/skills/index.js +28 -0
- package/dist/skills/load.js +118 -0
- package/dist/skills/manage.js +201 -0
- package/dist/skills/registry.js +138 -0
- package/dist/skills/render.js +124 -0
- package/dist/skills/sections.js +171 -0
- package/dist/skills/types.js +21 -0
- package/dist/subagent/codes.js +50 -0
- package/dist/subagent/declarative.js +55 -0
- package/dist/subagent/index.js +19 -0
- package/dist/subagent/notify.js +51 -0
- package/dist/subagent/provide.js +7 -0
- package/dist/subagent/registry.js +149 -0
- package/dist/subagent/service.js +338 -0
- package/dist/subagent/surface.js +44 -0
- package/dist/subagent/tool.js +153 -0
- package/dist/subagent/types.js +25 -0
- package/dist/tools/apply-patch.js +164 -0
- package/dist/tools/codes.js +109 -0
- package/dist/tools/fs.js +501 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/observed.js +99 -0
- package/dist/tools/pipeline.js +176 -0
- package/dist/tools/protected-read.js +54 -0
- package/dist/tools/registry.js +250 -0
- package/dist/tools/search.js +451 -0
- package/dist/tools/worktree.js +327 -0
- package/dist/web/codes.js +37 -0
- package/dist/web/gate.js +43 -0
- package/dist/web/hygiene.js +195 -0
- package/dist/web/index.js +16 -0
- package/dist/web/service.js +207 -0
- package/dist/web/ssrf-guard.js +44 -0
- package/dist/web/tool.js +76 -0
- package/dist/web/types.js +10 -0
- package/dist/webui/assets/index-B-t2O8gh.js +22 -0
- package/dist/webui/assets/index-DOlgSZ9Q.css +2 -0
- package/dist/webui/index.html +14 -0
- package/dist/webui/index.js +14 -0
- package/dist/webui/server.js +549 -0
- package/dist/webui/types.js +38 -0
- package/examples/README.md +26 -0
- package/examples/minimal-code-plugin/entry.js +43 -0
- package/examples/minimal-code-plugin/package.json +12 -0
- package/examples/pure-skill-pack/package.json +14 -0
- package/examples/pure-skill-pack/skills/markdown-table/SKILL.md +32 -0
- package/package.json +86 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP 实例(03 §10.2 生命周期——惰性 per-(server, rootUri) 单实例的承载腿)。
|
|
3
|
+
*
|
|
4
|
+
* connect 编舞:spawn(exec 管道窄面,owner = `lsp:<server>`)→ stderr 转
|
|
5
|
+
* logger debug → initialize 握手(startup_timeout_sec 钟只罩 spawn+握手)→
|
|
6
|
+
* initialized 通知。连接期失败抛 LSP_CONNECT_FAILED(子进程收场不留孤儿)。
|
|
7
|
+
*
|
|
8
|
+
* 文档同步(Full 全文同步——盘真相):`syncDocument` 首触 didOpen(携
|
|
9
|
+
* languageId)、后续 didChange(Full 全文 + 递增 version)——不维护影子文
|
|
10
|
+
* 本,文件即事实源;`closeDocument` 唯一触发点 = edit 的 delete 路径。
|
|
11
|
+
*
|
|
12
|
+
* 诊断 version 对齐:waiter 解锁 = 收到的诊断 version ≥ 本次发送 version
|
|
13
|
+
* (服务器不带 version 视为最新)——连续双写同文件不被过期诊断误唤醒。
|
|
14
|
+
*
|
|
15
|
+
* close(协议化关停):`shutdown` 请求 → 响应后发 `exit` 通知 → 宽限 →
|
|
16
|
+
* killTree 兜底;幂等(二次 close 复用同一结算)。
|
|
17
|
+
*
|
|
18
|
+
* crash:onExit close 事件 → failAll + onDown 一次送达(迟到订阅即回调)
|
|
19
|
+
* ——「一次进程事故恰计一败」的幂等闸在本层(markDown 一次结算)。
|
|
20
|
+
*/
|
|
21
|
+
import { BaseError } from '../contracts/index.js';
|
|
22
|
+
import { createLogger } from '../context/index.js';
|
|
23
|
+
import { LspWire } from './connection.js';
|
|
24
|
+
import { LSP_CLOSE_GRACE_MS, LSP_STARTUP_TIMEOUT_SEC_DEFAULT, languageIdForPath } from './types.js';
|
|
25
|
+
/** 连接单实例(握手全程)。连接期失败抛 LSP_CONNECT_FAILED,子进程先收场。 */
|
|
26
|
+
export async function connectLspInstance(server, config, rootUri, deps) {
|
|
27
|
+
const logger = deps.logger ?? createLogger('lsp');
|
|
28
|
+
const graceMs = deps.closeGraceMs ?? LSP_CLOSE_GRACE_MS;
|
|
29
|
+
const startupMs = (config.startup_timeout_sec ?? LSP_STARTUP_TIMEOUT_SEC_DEFAULT) * 1_000;
|
|
30
|
+
// ── spawn(登记簿同册:owner = lsp:<server>——「谁开的」审计面) ──
|
|
31
|
+
let child;
|
|
32
|
+
try {
|
|
33
|
+
child = deps.spawn.spawnInteractive({
|
|
34
|
+
argv: [config.command, ...(config.args ?? [])],
|
|
35
|
+
env: config.env !== undefined ? { set: config.env } : undefined,
|
|
36
|
+
owner: `lsp:${server}`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
throw new BaseError('LSP_CONNECT_FAILED', `spawn 失败(${server}):${errText(err)}`, { cause: asError(err) });
|
|
41
|
+
}
|
|
42
|
+
// ── 载体状态机(crash 检测 = close 事件;帧 fatal = 封读+同步树杀) ──
|
|
43
|
+
let downReason;
|
|
44
|
+
const downCallbacks = [];
|
|
45
|
+
let exitInfo;
|
|
46
|
+
const exitWaiters = [];
|
|
47
|
+
let closePromise;
|
|
48
|
+
let wire;
|
|
49
|
+
const markDown = (reason) => {
|
|
50
|
+
if (downReason !== undefined)
|
|
51
|
+
return; // 幂等闸:一次进程事故恰计一败
|
|
52
|
+
downReason = reason;
|
|
53
|
+
for (const cb of [...downCallbacks])
|
|
54
|
+
cb(reason);
|
|
55
|
+
for (const w of [...exitWaiters])
|
|
56
|
+
w();
|
|
57
|
+
exitWaiters.length = 0;
|
|
58
|
+
};
|
|
59
|
+
child.onExit((info) => {
|
|
60
|
+
exitInfo = info;
|
|
61
|
+
wire?.failAll(new BaseError('LSP_CONNECT_FAILED', info.spawnError !== undefined
|
|
62
|
+
? `spawn 失败(${server}):${info.spawnError.message}`
|
|
63
|
+
: `LSP 服务器退出(${server},code=${info.code})`));
|
|
64
|
+
markDown(info.spawnError !== undefined ? `spawn 失败:${info.spawnError.message}` : `服务器退出(code=${info.code})`);
|
|
65
|
+
});
|
|
66
|
+
// ── 文档同步账(per-URI version——盘真相全文同步) ──
|
|
67
|
+
const docs = new Map();
|
|
68
|
+
/** 诊断账:uri → 最近一帧(version 对齐判据用) */
|
|
69
|
+
const latestDiag = new Map();
|
|
70
|
+
const diagWaiters = [];
|
|
71
|
+
wire = new LspWire({
|
|
72
|
+
send: (frame) => child.stdin.write(frame),
|
|
73
|
+
warn: (message) => logger.warn(message),
|
|
74
|
+
onFatal: () => {
|
|
75
|
+
// 载体级失败收场:封读 + 同步树杀(不杀即永久孤儿)
|
|
76
|
+
child.stdout.destroy();
|
|
77
|
+
child.kill();
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
child.stdout.on('data', (chunk) => wire?.feed(chunk));
|
|
81
|
+
child.stderr.on('data', (chunk) => {
|
|
82
|
+
for (const line of chunk.toString('utf8').split('\n')) {
|
|
83
|
+
if (line.trim() !== '')
|
|
84
|
+
logger.debug(`[lsp:${server}] ${line}`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// publishDiagnostics 唯一真消费面:记账 + 唤醒满足 version 对齐的 waiter
|
|
88
|
+
wire.onNotification('textDocument/publishDiagnostics', (n) => {
|
|
89
|
+
const p = (n.params ?? {});
|
|
90
|
+
if (typeof p.uri !== 'string')
|
|
91
|
+
return;
|
|
92
|
+
const items = normalizeDiagnostics(p.diagnostics);
|
|
93
|
+
const version = typeof p.version === 'number' ? p.version : undefined;
|
|
94
|
+
latestDiag.set(p.uri, { version, items });
|
|
95
|
+
for (let i = diagWaiters.length - 1; i >= 0; i--) {
|
|
96
|
+
const w = diagWaiters[i];
|
|
97
|
+
if (w.uri !== p.uri)
|
|
98
|
+
continue;
|
|
99
|
+
// version 对齐:不带 version 视为最新;带则须 ≥ 本次发送 version
|
|
100
|
+
if (version === undefined || version >= w.minVersion) {
|
|
101
|
+
clearTimeout(w.timer);
|
|
102
|
+
diagWaiters.splice(i, 1);
|
|
103
|
+
w.resolve(items);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
try {
|
|
108
|
+
// ── initialize 握手(startup 钟只罩 spawn+握手;rootUri 钉工作区物理根) ──
|
|
109
|
+
await wire.request('initialize', { processId: null, rootUri, capabilities: {} }, startupMs);
|
|
110
|
+
wire.notify('initialized', {});
|
|
111
|
+
if (downReason !== undefined) {
|
|
112
|
+
throw new BaseError('LSP_CONNECT_FAILED', `LSP 服务器退出(${server}):${downReason}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// 连接期失败收场:结清 pending + 树杀(不留孤儿)→ 分类抛出
|
|
117
|
+
wire.failAll(err instanceof BaseError ? err : new BaseError('LSP_CONNECT_FAILED', `握手失败(${server}):${errText(err)}`));
|
|
118
|
+
child.kill();
|
|
119
|
+
if (err instanceof BaseError && err.code === 'LSP_CONNECT_FAILED')
|
|
120
|
+
throw err;
|
|
121
|
+
if (err instanceof Error && err.message.includes('超时')) {
|
|
122
|
+
throw new BaseError('LSP_CONNECT_FAILED', `initialize 握手超时(${server},预算 ${startupMs}ms)`, {
|
|
123
|
+
cause: err,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
throw new BaseError('LSP_CONNECT_FAILED', `握手失败(${server}):${errText(err)}`, { cause: asError(err) });
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
server,
|
|
130
|
+
rootUri,
|
|
131
|
+
request: (method, params, timeoutMs) => {
|
|
132
|
+
if (downReason !== undefined) {
|
|
133
|
+
return Promise.reject(new BaseError('LSP_CONNECT_FAILED', `实例已死(${server}):${downReason}`));
|
|
134
|
+
}
|
|
135
|
+
return wire.request(method, params, timeoutMs);
|
|
136
|
+
},
|
|
137
|
+
syncDocument(uri, text, path) {
|
|
138
|
+
const doc = docs.get(uri);
|
|
139
|
+
if (doc === undefined) {
|
|
140
|
+
// 首触:didOpen 携 languageId(version 从 1 起)
|
|
141
|
+
docs.set(uri, { version: 1 });
|
|
142
|
+
wire.notify('textDocument/didOpen', {
|
|
143
|
+
textDocument: { uri, languageId: languageIdForPath(path), version: 1, text },
|
|
144
|
+
});
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
doc.version += 1;
|
|
148
|
+
wire.notify('textDocument/didChange', {
|
|
149
|
+
textDocument: { uri, version: doc.version },
|
|
150
|
+
contentChanges: [{ text }], // Full 全文同步——增量算法不进 v1
|
|
151
|
+
});
|
|
152
|
+
return doc.version;
|
|
153
|
+
},
|
|
154
|
+
closeDocument(uri) {
|
|
155
|
+
if (!docs.has(uri))
|
|
156
|
+
return; // 未开不关(幂等)
|
|
157
|
+
docs.delete(uri);
|
|
158
|
+
wire.notify('textDocument/didClose', { textDocument: { uri } });
|
|
159
|
+
},
|
|
160
|
+
latestDiagnostics(uri, minVersion) {
|
|
161
|
+
const latest = latestDiag.get(uri);
|
|
162
|
+
if (latest === undefined)
|
|
163
|
+
return undefined;
|
|
164
|
+
if (latest.version !== undefined && latest.version < minVersion)
|
|
165
|
+
return undefined; // 过期帧不算
|
|
166
|
+
return latest.items;
|
|
167
|
+
},
|
|
168
|
+
waitDiagnostics(uri, minVersion, timeoutMs) {
|
|
169
|
+
// 快路径:已满足 version 对齐的最近帧直取(零等待)
|
|
170
|
+
const latest = latestDiag.get(uri);
|
|
171
|
+
if (latest !== undefined && (latest.version === undefined || latest.version >= minVersion)) {
|
|
172
|
+
return Promise.resolve(latest.items);
|
|
173
|
+
}
|
|
174
|
+
return new Promise((resolve) => {
|
|
175
|
+
const entry = {
|
|
176
|
+
uri,
|
|
177
|
+
minVersion,
|
|
178
|
+
resolve: (items) => {
|
|
179
|
+
// 连接死等价超钟——null 诚实降级(调用方逐路径点名)
|
|
180
|
+
resolve(items);
|
|
181
|
+
},
|
|
182
|
+
timer: setTimeout(() => {
|
|
183
|
+
const idx = diagWaiters.indexOf(entry);
|
|
184
|
+
if (idx >= 0)
|
|
185
|
+
diagWaiters.splice(idx, 1);
|
|
186
|
+
resolve(null);
|
|
187
|
+
}, timeoutMs),
|
|
188
|
+
};
|
|
189
|
+
diagWaiters.push(entry);
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
onDown(callback) {
|
|
193
|
+
if (downReason !== undefined)
|
|
194
|
+
callback(downReason); // 迟到订阅即回调
|
|
195
|
+
else
|
|
196
|
+
downCallbacks.push(callback);
|
|
197
|
+
},
|
|
198
|
+
close: () => {
|
|
199
|
+
if (closePromise === undefined) {
|
|
200
|
+
closePromise = closeChild(wire, child, graceMs, () => exitInfo, (waiter) => exitWaiters.push(waiter), logger, server);
|
|
201
|
+
}
|
|
202
|
+
return closePromise; // 幂等——二次 close 复用首次结算
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/** publishDiagnostics.diagnostics 归一(坏条目跳过——range/severity/message 容错) */
|
|
207
|
+
function normalizeDiagnostics(raw) {
|
|
208
|
+
if (!Array.isArray(raw))
|
|
209
|
+
return [];
|
|
210
|
+
const items = [];
|
|
211
|
+
for (const entry of raw) {
|
|
212
|
+
if (typeof entry !== 'object' || entry === null)
|
|
213
|
+
continue;
|
|
214
|
+
const d = entry;
|
|
215
|
+
if (typeof d.message !== 'string')
|
|
216
|
+
continue;
|
|
217
|
+
items.push({
|
|
218
|
+
severity: typeof d.severity === 'number' ? d.severity : 1,
|
|
219
|
+
message: d.message,
|
|
220
|
+
line: typeof d.range?.start?.line === 'number' ? d.range.start.line : 0,
|
|
221
|
+
character: typeof d.range?.start?.character === 'number' ? d.range.start.character : 0,
|
|
222
|
+
...(typeof d.source === 'string' ? { source: d.source } : {}),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return items;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* 协议化关停编舞:shutdown 请求 → 响应后发 exit 通知 → 宽限 → killTree
|
|
229
|
+
* 兜底。shutdown 无响应(挂死/已死)不等满——请求钟与宽限同帽,钟尽即发
|
|
230
|
+
* exit 进入宽限段(关停不因坏服务器悬挂)。
|
|
231
|
+
*/
|
|
232
|
+
function closeChild(wire, child, graceMs, exitOf, addWaiter, logger, server) {
|
|
233
|
+
return (async () => {
|
|
234
|
+
// shutdown 请求(响应与否都进 exit 段——宽限钟即本段总帽)
|
|
235
|
+
await wire.request('shutdown', undefined, graceMs).catch(() => undefined);
|
|
236
|
+
try {
|
|
237
|
+
wire.notify('exit');
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// 已死载体——宽限/树杀照走
|
|
241
|
+
}
|
|
242
|
+
const exited = new Promise((resolve) => {
|
|
243
|
+
if (exitOf() !== undefined)
|
|
244
|
+
resolve();
|
|
245
|
+
else
|
|
246
|
+
addWaiter(resolve);
|
|
247
|
+
});
|
|
248
|
+
const raced = await Promise.race([exited.then(() => true), delay(graceMs).then(() => false)]);
|
|
249
|
+
if (!raced) {
|
|
250
|
+
logger.warn(`LSP 实例宽限尽未退(${server})——树杀兜底`);
|
|
251
|
+
child.kill();
|
|
252
|
+
}
|
|
253
|
+
})();
|
|
254
|
+
}
|
|
255
|
+
/** 延时助手(宽限钟) */
|
|
256
|
+
function delay(ms) {
|
|
257
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
258
|
+
}
|
|
259
|
+
function errText(err) {
|
|
260
|
+
return err instanceof Error ? err.message : String(err);
|
|
261
|
+
}
|
|
262
|
+
function asError(err) {
|
|
263
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
264
|
+
}
|