使用说明
spectatty(spectate tty)
使用AI代理构建TUI应用程序的工具包。代理可以生成真实的终端会话,像人类一样与它们交互,对渲染的输出进行截图,并与您共享实时会话——这样他们就可以在构建UI时实际查看和调试UI,而不是从原始文本中猜测。
暴露为 MCP服务器 (和CLI),因此任何支持MCP的代理都可以开箱即用。
的问题
如今,每个人都在用人工智能构建终端应用程序(包括我自己),但很常见的情况是陷入以下循环:提示更改->手动测试UI->告诉代理出了什么问题->重复。代理人基本上是盲目的。
在构建web应用程序时,这不是问题——像这样的工具 剧作家 让代理在构建渲染的UI时检查并与之交互。TUI应用程序没有等效的工具。这就是为什么这很难。
哪些代理当前可以访问以查看终端输出:
tmux capture-pane -剥离所有颜色和样式,返回原始文本:
| htop | 开放代码 |
|---|---|
与此同时,从人类的角度来看,UI实际上是这样的:
| htop | 开放代码 |
|---|---|
spectatty为代理商提供了什么:
使用spectatty,代理实际上可以从人类的角度渲染和截图UI,包括间距、颜色、字体等。这允许它调试在纯文本视图中甚至不可见的UI错误(例如,您可能正在使用颜色来指示UI中的边界,或者组件之间的间距可能会微妙地偏离)。
| htop | 开放代码 |
|---|---|
演示
给代理人的提示:
我的CLI目前显示暗淡和不暗淡的文本,用于思考和非思考输出。请将此更改为使用蓝色表示思考,使用绿色表示文本。记录mp4前后的变化,显示变化的全部范围。
代理进行代码更改,然后自主记录MP4前后的结果。在下面的视频中,左侧终端是在Claude Code中工作的代理。右侧终端是代理的spectatty会话的实时视图,通过 spectatty attach --所有的输入都是由代理完成的,而不是用户。
https://github.com/user-attachments/assets/0a76b7f6-4b0a-4bf3-a650-4cd0517cc7a1
在MP4之前和之后,该试剂产生了:
| 之前 | 之后 |
|---|---|
spectatty解决的其他问题
-
生成一个真正的终端 -bash工具通常是带有管道stdio的子进程,而不是完整的PTY。依赖于终端大小、交替屏幕、鼠标输入或原始按键的TUI应用程序会在bash工具中崩溃。spectatty生成了一个由无头终端模拟器支持的真正的PTY,因此您可以测试全套终端行为。
-
在适当的抽象层次上进行交互 -编写原始转义序列是灵活的,但不可读。如果探员告诉你它跑了
\x1b[A\x1b[Acontinue\r你不知道它做了什么。斯佩克蒂揭露了离散的类人行为(terminal_type,terminal_key,terminal_ctrl等等),因此代理痕迹是可读和可再现的。原始逃生通道仍可通过terminal_write作为最后的手段-如果代理必须使用它,这通常意味着操作集存在缺口或应用程序存在问题。 -
人类合作 -两部分。首先,用户如何看到代理正在做什么?
spectatty attach <sessionId>允许您在自己的终端中实时观看实时代理驱动的会话。terminal_screenshot接受asavePath因此用户可以编写和查看PNG。第二,用户如何共享上下文?自己跳到附件中的会话spectatty attach <sessionId>,再现一个错误,代理下次截图时会看到结果。
运作原理
bun-pty (spawn process in a real PTY)
-> @xterm/headless (parse escape sequences into virtual screen buffer)
-> @napi-rs/canvas (render cell grid to PNG)
-> MCP server (expose as tools over stdio)
MCP服务器委托给拥有PTY会话的长时间运行的守护进程。程序写入的每个字节都经过 xterm.js 进程中,因此渲染的屏幕始终是最新的,无需轮询。每个会话的Unix套接字允许人类连接并实时观看。
工具
输入
| 工具 | 说明 |
|---|---|
terminal_type |
键入文本,就像用户一样。添加 submit: true 之后按Enter键。优先选择 terminal_write 用于文本输入。 |
terminal_key |
按指定键: enter, backspace, tab, escape, up/down/left/right, page_up/page_down, home/end, f1--f12.支持 times 重复。 |
terminal_ctrl |
发送Ctrl+组合键: c (中断), d (EOF), z (暂停), l (清晰)等。 |
terminal_send_scroll |
向上或向下发送滚动输入。 |
terminal_mouse |
在特定列/行位置发送鼠标事件(单击、移动、向下、向上)。 |
terminal_write |
发送带有转义序列的原始输入(\r, \x03, \e).最后手段-首选上述工具。 |
观察
| 工具 | 说明 |
|---|---|
terminal_screenshot |
将当前屏幕捕获为PNG、纯文本或两者兼而有之。 savePath 将PNG写入磁盘。 viewportTop 在捕获之前滚动到特定行 |
terminal_wait_for |
等待正则表达式模式出现在终端文本中。投票,直到匹配或超时。 |
terminal_list |
列出所有活动会话及其维度和退出状态。 |
会话生命周期
| 工具 | 说明 |
|---|---|
terminal_spawn |
生成一个新的终端会话。返回a sessionId 以及连接插座的路径。 |
terminal_resize |
将会话调整为新尺寸。 |
terminal_kill |
终止一个会话并清理所有资源。 |
录制
| 工具 | 说明 |
|---|---|
terminal_record_start |
开始将终端输出记录为 asciicast v2 .cast 文件。 |
terminal_record_stop |
停止录制。保存 .cast 文件并自动写入sidecar .tape.json 沿着它(相同的路径, .cast 扩展名替换为 .tape.json). |
terminal_to_gif |
转换a .cast 录制为动态GIF(需要 agg). |
terminal_to_mp4 |
转换a .cast 录制为MP4视频(需要 ffmpeg). |
terminal_export_tape |
将会话的交互日志导出为可回放 .tape.json 文件。 |
terminal_replay_tape |
重播a .tape.json 并返回实时会话ID |
命令行界面
spectatty <subcommand>
| 子命令 | 描述 |
|---|---|
mcp |
在stdio上启动MCP服务器 |
server start/stop/status |
管理后台守护进程 |
ctl <subcommand> |
控制终端会话(镜像所有MCP工具-见下文) |
attach <sessionId> |
将您的终端连接到实时会话。用途 Ctrl+A 作为控制命令的前缀键-按Ctrl+a,然后: d 为了分离, l 获取代理锁(阻止代理写入,以便您可以自由键入), u 为了解锁, s 在锁定状态下进行屏幕截图。按Ctrl+a两次发送文字Ctrl+a。如果你卡住了,按Ctrl+A d 总是退出。 |
tail <file.cast> |
实时跟踪正在编写的asciicast录音 |
to-gif <input.cast> <output.gif> |
将录制转换为动态GIF(需要 agg) |
to-mp4 <input.cast> <output.mp4> |
将录音转换为MP4(需要 ffmpeg) |
replay-cast <file.cast> |
播放a .cast 当前终端中具有原始定时的文件 |
replay-tape <file.tape.json> |
重放磁带文件。产生a .cast 默认情况下; --live 回放到当前终端。 |
spectatty ctl 将每个MCP工具作为脚本和调试的子命令公开: spawn, list, type, key, ctrl, write, screenshot, resize, kill, scroll, mouse, wait-for, record-start, record-stop, export-tape, replay-tape.
安装
需要 包子 (v1.0+)。这 to-gif 和 to-mp4 命令还需要 agg 和 ffmpeg 分别。
bun install -g spectatty
spectatty mcp
用法
MCP客户端配置
添加到您的MCP客户端配置中(例如Claude Desktop、Cursor等):
{
"mcpServers": {
"spectatty": {
"command": "spectatty",
"args": ["mcp"]
}
}
}
注: 如果
spectatty如果不在MCP客户端的PATH中,请使用完整路径(例如。~/.bun/bin/spectatty).
发展
git clone https://github.com/dayvidwang/spectatty
cd spectatty
bun install
bun run src/cli.ts mcp
交互示例
1. terminal_spawn(cols: 220, rows: 50) -> { sessionId: "term-1", attachSocket: "/tmp/spectatty-*.sock" }
2. terminal_type(sessionId: "term-1", text: "vim file.txt", submit: true)
3. terminal_wait_for(sessionId: "term-1", pattern: "vim")
4. terminal_screenshot(sessionId: "term-1") -> PNG + text of vim loaded
5. terminal_key(sessionId: "term-1", key: "i") -> enter insert mode
6. terminal_type(sessionId: "term-1", text: "hello world")
7. terminal_key(sessionId: "term-1", key: "escape")
8. terminal_type(sessionId: "term-1", text: ":wq", submit: true)
9. terminal_screenshot(sessionId: "term-1") -> confirm file saved
10. terminal_kill(sessionId: "term-1")
与此同时,人类可以奔跑 spectatty attach term-1 观看会议直播。
堆栈
| 层 | 包 |
|---|---|
| PTY | 包子pty |
| 终端仿真 | @xterm/无头 |
| PNG渲染 | @纳帕/帆布 |
| HTML序列化 | @xterm/addon序列化 |
| MCP服务器 | @模型上下文协议/sdk |
设计说明
为什么不组合tmux+asciinema?
显而易见的替代方案是使用现有的工具:tmux用于会话管理,asciinema用于录制,VHS作为脚本交互的参考。
核心问题: tmux capture-pane 仅为快照(您轮询它)。 tmux pipe-pane 流式传输原始PTY字节,但要从这些字节中生成屏幕截图,您仍然需要自己通过终端模拟器解析它们。无论如何,您最终都会重新实现渲染管道,在中间会有一个额外的子流程跃点。
所需的基本属性是 渲染状态始终为最新,零轮询。这需要直接拥有PTY,这样xterm.js就可以在每个字节到达时处理它。
家用录像系统 是最接近的精神前身——它驱动一个无头终端并呈现输出。不同之处在于,VHS是一个批处理工具(脚本输入->视频输出),而spectatty是交互式的(代理实时驱动会话,在任意点截图,等待模式,无限期保持会话活动)。
许可证
麻省理工学院