Volume 2 · Chapter 27
终端与 LSP:subprocess 之上的持久交互
终端(terminal)是「持久会话的交互式 shell」——16 页的 subprocess 有进程树管理,但没有「会话持续」的语义。终端 seam 在它之上加持久层。LSP 是语言服务器协议客户端——让模型读写代码符号而非文本。两者都是 16 页下层 seam 的消费者。
(卷一连接点) 16 页 subprocess(PTY/进程树)· 15 页 seam 模板
→
本域:terminal / terminal-bash / tool-terminal* / lsp / lsp-stdio
→
(回心脏) 终端的增量输出经 jobs(25 页)或直接进工具结果
示例本次示例:跨多次工具调用的终端会话
示例轨迹 27-1 · 终端 vs 普通 bash 的差异
# 普通 bash(17 页):每次调用 spawn 新进程
# bash("pwd") → 新 bash → 退出;bash("cd x && pwd") → 又一个新 bash
# 终端(terminal-bash,inject=['terminals','sandboxPolicy','subprocess']):
# terminal_exec("pwd") → 会话 t1 的 PTY 进程执行
# terminal_exec("cd src") → 同一 PTY,目录状态保留
# terminal_exec("pwd") → /workspace/src(前一条 cd 生效了)
# 持久性在 TerminalSessionService(terminal/src/index.ts:105)的契约里
来源:27 页 §3 + 16 页 spawnTerminal
示例轨迹 27-2 · LSP 的结构化问答
# 模型:lsp("auth.ts 里 authenticate 的定义在哪?")
# lsp-stdio(inject=['fs','lsp','subprocess']):
# subprocess.spawn 语言服务器进程(16 页下层)
# JSON-RPC: textDocument/definition → 结果 {file:'src/auth.ts', line:42}
# 对比 grep 文本搜索:LSP 给的是符号级答案
# 换 subprocess provider(e2b 远程)→ LSP 与终端一起搬(15 页结论)
来源:27 页 §3 + 15 页共享执行世界
§1挂载条目
terminal-bash → dsh-terminal-bash(1116 行,可选挂载)——inject = ['terminals', 'sandboxPolicy', 'subprocess'](src/index.ts:26)lsp-stdio → dsh-lsp-stdio(1664 行,可选挂载)——inject = ['fs', 'lsp', 'subprocess'](src/index.ts:47)- tool-terminal* / tool-lsp* 家族(模型可见工具,部分在 profile 层追加)
§2包文件地图
| 包 | 规模 | 角色 |
|---|---|---|
packages/terminal/terminal/ | — | Service Definition:TerminalSessionService extends Service(src/index.ts:105)——持久终端会话契约 |
packages/terminal/terminal-bash/ | 5 文件 / 1116 行 | Provider:bash 终端——依赖 terminals + sandboxPolicy + subprocess(16 页的下层) |
packages/lsp/lsp/ | — | Service Definition:Lsp extends Service implements LspService(src/index.ts:82) |
packages/lsp/lsp-stdio/ | 9 文件 / 1664 行 | Provider:stdio 传输的语言服务器——inject = ['fs','lsp','subprocess'] |
§3机制:持久会话与语言服务器
- terminal = subprocess + 持久:普通 bash 命令每次 spawn 新进程;终端会话保持一个 PTY 进程跨多次工具调用存活(增量输出、前台进程组)。16 页的 spawnTerminal 与进程树清理就是它的底座。
- lsp = 结构化代码访问:LSP 协议让模型做符号级操作(定义跳转、引用、补全),而不是 grep 文本。stdio provider 通过 subprocess spawn 语言服务器进程,走 JSON-RPC。
- 两者都站在 16 页的下层上:换 subprocess provider(如 e2b 远程)时,terminal 和 lsp 一起跟着搬——15 页「共享执行世界」结论的第二个例子。
§4关键代码
105export class TerminalSessionService extends Service {
47export const inject = ['fs', 'lsp', 'subprocess']
105
terminal 的 Definition。持久会话的语义都在这里(会话生命周期、增量读取、前台控制)。
47
lsp-stdio 的依赖面说明了它的位置:fs(读文件)、lsp(自己注册进 seam)、subprocess(spawn 语言服务器进程)。三个 seam 叠三层。
§5易错点
终端会话的存活边界比命令长:17 页的「executor-only 重载后后台进程存活」在终端上更显著——终端会话绑定 subprocess provider,重载 terminal provider 不杀进程(与 16 页同一条边界)。
PTY 的前台进程组检测:16 页提过的 process-inspector(Linux /proc、macOS ps)在 0.1.3-alpha.2 新增了 windows-inspector(325 行)——三平台进程表探测齐全。这是 terminal 正确清理会话树的前提。