mcpField
T
tty7

tty7

github.com/l0ng-ai开发1.4k114 次安装1 天前更新
代码仓库

关于 tty7

tty7 是用于通过命令行操作 tty7 服务的非交互式客户端,适合需要管理终端窗格和委派编码任务的 Agent。它支持启动命令、读写窗格、等待命令或 Agent 状态,并可输出机器可读结果。

主要功能

  1. 01运行阻塞式或后台命令
  2. 02向窗格发送文本和按键
  3. 03捕获并读取窗格内容
  4. 04等待命令或 Agent 状态变化
  5. 05检查进程、端口和服务状态

适用场景

  1. 01在可见终端窗格运行开发服务器
  2. 02连接并操作 REPL、SSH 或调试器
  3. 03查看其他窗格中的进程与输出
  4. 04将编码任务委派给其他 Agent

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/l0ng-ai/tty7 --skill tty7

安装后在 Claude Code 中输入/tty7确认已加载。

附带文件references/commands.mdreferences/delegation.md

详细介绍

从命令行驱动 tty7

tty7 是 tty7 服务端的轻量级非交互客户端。每个动词都会返回并退出;--json 会让输出变为机器可读。GUI 不必运行——负责管理窗格的是服务端。

首先:你身处何处?

tty7 doctor

一张表就能回答你开始操作前需要了解的所有信息:服务端是否可访问、协议是否匹配、每个 Agent 的状态钩子是否已安装,以及是否设置了 TTY7_CONFIG_DIR / TTY7_WS / TTY7_PANE——也就是说,你是否正在 tty7 窗格内运行。

身处窗格内有两个重要原因:需要地址的动词(split、send、exec、capture、procs、wait、pane close)默认使用 $TTY7_PANE,而 run --keep 会将其窗格归入 $TTY7_WS。在 tty7 shell 外,你必须明确指定目标;否则会直接提示错误,而不是擅自猜测。

如果你打算委派任务给另一个 Agent,钩子这一行就很重要:没有这些钩子,Agent 不会报告状态,因此对其运行 tty7 wait 只会超时。

如果 tty7 doctor 显示服务端无法访问,请停止操作并告知用户——不要自行运行 tty7 server start。启动用户未要求启动的服务端,会改变其 GUI 所连接的对象。

你要做什么?

四种任务,四种方式:

  1. 运行不应阻塞你的任务,或需要真实 TTY 的任务——开发服务、长时间测试运行、TUI。运行命令。
  2. 与需要持续交互的对象对话——REPL、ssh、调试器。使用相同的基本操作:发送、读取、重复。
  3. 查看这台机器正在做什么——其他窗格、其他 Agent、端口。查看周边情况,严格只读。
  4. 将工作交给另一个编码 Agent——一个工作者,或同时分派给多个工作者。请先阅读 references/delegation.md;简要说明见下文。

对于任何启动后自行完成任务并退出,且不需要终端或旁观者的操作,Bash 工具仍然是合适的选择。当进程的生命周期超出你的当前操作、需要真实 PTY,或应在用户的 tty7 窗口中可见时,窗格才真正派得上用场——最后一种情况往往正是使用窗格的全部目的。

地址

形式含义稳定?
%42一个窗格是 — 窗格在其整个生命周期内都保留同一 ID
@7一个标签页,按整个机器的树形顺序编号否 — 工作区或标签页出现或消失时,编号都会变化
@<full tab UUID>通过 ID 指定同一个标签页是
api / 76698a44 / 一个完整的 UUID一个工作区,可按名称、唯一 ID 前缀或 ID 指定是

使用前应重新解析 @N;创建或删除标签页的步骤前后,切勿缓存其编号。窗格 ID、标签页 ID 和工作区 ID 都可以安全记住——因此,创建标签页后若要再次指定它,请保留 tty7 tab new --json 返回的 ID,而不要再次按顺序数出 @N。

在任何需要地址的位置,标记符都可以省略:%42 和 42 表示同一个窗格,@7 和 7 表示同一个标签页。从 --json 中复制的 ID 可以直接粘贴回来。

在 tty7 shell 中省略地址,表示“此窗格”/“此工作区”。显式指定的地址始终优先于环境变量。

运行命令:三种方式

阻塞运行,并返回真实退出码
tty7 run -- cargo test          # streams to your stdout, exits with cargo's code
tty7 run --cwd /path -- make
tty7 run --keep -- cargo build  # leaves the pane as a new tab afterwards

命令输出会实时流式传输到你的 stdout,tty7 会以命令自身的退出码退出。这是最接近 Bash 调用的方式——不同之处在于它使用 PTY,而且用户可以看到输出。

有三点需要注意。--keep 需要工作区,因此只能在 tty7 shell 中使用,或配合 --ws <workspace> 使用。使用 --json 时,流式输出会先出现,JSON 对象最后出现——合并后的流不能作为 JSON 解析,因此请读取最后一行。窗格宽度为 120 列,无法更改,因此假定终端更宽的输出会发生换行。

阻塞式:在已有窗格中执行
tty7 exec "$PANE" --timeout 900 -- cargo test   # prints its output, exits with its code

exec 会在窗格的 shell 提示符处输入这一行——使用该窗格的当前工作目录、环境和历史记录——等待提示符重新出现,输出命令打印的内容(以文本形式,与 capture --plain 一样;--raw 会保留转义序列),然后以命令自身的退出码退出。这样,你就能在之前已设置好的窗格中运行下一条命令(例如 cd、已激活虚拟环境,或远端已启用 tty7 shell 集成的 ssh 会话),不用再经历发送、等待、捕获、猜测这一套操作。

它所需的条件,以及不满足时的提示:窗格的 shell 必须启用 tty7 shell 集成(从未发送过提示符标记的窗格会被拒绝),而且窗格必须停留在提示符处(忙碌的窗格会被拒绝——请先执行 wait --until free)。-- 后面的内容会成为一整行 shell 命令,因此只要加上引号,&&、管道和重定向都可以正常使用:tty7 exec %3 -- 'make && ./run'。无人监看时,务必指定 --timeout:如果 shell 始终没有运行这一行——例如未闭合的引号一直等待 dquote>——就会一直等不到结束。超时后会以 124 退出,并让命令继续运行。

非阻塞式:随时可以交互的窗格

这正是 tty7 值得使用的地方。获取一个窗格,给它发送任务,之后再回来查看。

PANE=$(tty7 split --v)                  # or --h; splits $TTY7_PANE, prints "%83"
tty7 send "$PANE" 'npm run dev' --enter

split 会将新窗格的地址打印到 stdout,你可以将其捕获到变量中。不指定轴向会导致用法错误——--v 会将新窗格放在下方,--h 会将其放在右侧。

拆分 $TTY7_PANE 会改变用户可见的布局,这通常正是目的所在:用户可以查看你启动的开发服务器。请告知用户你进行了拆分,并在用完后关闭窗格。

如果你不在 tty7 窗格中,就没有可供拆分的窗格,因此请先创建自己的工作位置。tty7 new --json /path/to/repo 会一次性返回两个 ID——不用从 ws tree 中翻找窗格:

read -r WS PANE < <(tty7 new --json /path/to/repo \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["id"], "%%%d" % d["pane"])')

send 会像键盘输入一样,将文本输入窗格;--enter 会在末尾附加回车,或者在未提供文本时单独按下 Enter(tty7 send "$PANE" --enter 会运行窗格中已输入的内容)。它不会等待,也不会告诉你发生了什么——读取是单独的步骤,等待则使用 tty7 wait。

若要发送按键而非字符——Ctrl-C、Escape、方向键——请使用 --key:它接受 enter escape tab backtab space backspace delete up down right left home end pageup pagedown,以及表示 Ctrl 的 C-<char> 和表示 Alt 的 M-<char>。按顺序发送多个按键时,请重复使用该选项;文本和按键可以组合,文本先发送。将 ^C 作为文本输入没有任何作用——它会作为两个字符送达;--key C-c 才是真正的中断。

命令行文本有两种做不到的事。机密信息:tty7 send %3 "$TOKEN" 会让本机所有用户都能在 ps 中看到令牌,也会将其写入 shell 历史记录——请改用管道:printf %s "$TOKEN" | tty7 send %3 --stdin --enter (或使用 --from-file PATH);字节会按读取到的内容原样发送到窗格,且绝不会回显到 --json 中。远端的回显由程序自行处理:docker login --password-stdin、ssh-add 和 gpg 都会自行关闭回显。 多行文本:在 pty 中,换行符就是 Enter,因此每一行到达时都会运行。--paste 会像粘贴到窗口中那样发送内容——如果窗格已启用括号粘贴模式,就会使用该模式发送,因此 shell 或 Agent 的输入框会将整块内容作为文本接收;--json 会报告 "bracketed",让你知道采用了哪种方式。

新建窗格可能会吞掉 Enter。 shell 仍在执行启动文件时——例如提示符框架、fastfetch,或任何会在登录时绘制内容的程序——会接收你发送的文本,却丢失其后跟随的回车,导致命令停留在提示符行上而未执行。不会有任何提示:send 已成功,窗格看起来却像是尚未启动的工作进程。因此,向刚创建的窗格发送第一条命令后,请读回屏幕并确认命令确实已离开提示符行:

tty7 capture "$PANE" --plain | tail -3   # command still sitting on the prompt?
tty7 send "$PANE" --enter                # then give it the Enter it lost

这比之后排查问题省事,而且只有向新窗格发送第一条命令时才需要检查。

阅读窗格

如果你想看屏幕,请使用 --plain
tty7 capture %83 --plain

capture 会返回守护进程存储的内容——窗格的字节、转义序列,一应俱全;而 --plain 会将其重新通过终端网格渲染,并打印生成的文本。它不只是去除转义序列:颜色和光标转义序列会消失,但被 Shell 按窗格宽度换行的内容也会还原为一行,使用 \r 重绘自身的进度条会显示最终值,TUI 的屏幕内容则会呈现为绘制时的样子。只要人需要阅读输出,就使用它。

无论哪种方式,返回结果都有两点需要注意:capture 返回的是快照,不是数据流——要获取更新的内容,请再次调用。默认情况下,它会打印最新的回滚片段(环形缓冲区会在调整大小时分段);--scrollback 会打印整个缓冲区。对于从未调整过大小的窗格,两者内容相同。

如果你想要结果,请将输出重定向到文件

--plain 返回的是屏幕,而屏幕是一个矩形:长篇构建日志中滚出顶部的内容已经消失,退出代码也从未显示在屏幕上。当窗格中的 Shell 正停在提示符处时,tty7 exec(见上文)会同时返回这两者。否则——窗格正忙,或其中的 Shell 没有集成 tty7——让 Shell 将答案写入一个干净的位置:

tty7 send "$PANE" 'cargo test > /tmp/t.log 2>&1; echo $? > /tmp/t.rc' --enter
# ...wait for it to finish (below), then:
cat /tmp/t.rc /tmp/t.log

完整输出、真实退出代码,终端不会介入。

判断命令何时完成

不要轮询屏幕,也不要自己编写循环——直接阻塞等待:

tty7 wait "$PANE" --until free --changed --timeout 900

free 表示前台命令已退出,窗格已恢复到空闲 Shell 状态。--changed 还会额外要求“等待期间确实有命令运行”,这正是你在 send 后紧接着执行时所需要的:如果没有它,尚未启动的命令会让窗格看起来像是已完成。

完整流程如下:

tty7 send "$PANE" 'cargo test > /tmp/t.log 2>&1; echo $? > /tmp/t.rc' --enter
tty7 wait "$PANE" --until free --changed --timeout 900
cat /tmp/t.rc /tmp/t.log
tty7 pane close "$PANE"

退出代码就是为此设计的:0 表示已达到你要求的状态,124 表示超时(遵循 timeout(1) 的约定,因此可以区分“尚未完成”和“出错”),1 表示窗格先行终止。

使用 --changed 时有个陷阱:如果命令在一次轮询内(默认 500ms)就完成,它就不会被观察到处于运行状态,因此等待会一直持续,直到超时。对于运行如此之快的命令,可以使用 --interval 100,或者去掉 --changed 并读取 .rc 文件。发生这种情况时,超时消息会说明原因。

如果你想查看进程树本身——“里面正在运行什么”“这个窗格在提供哪个端口的服务”——可以使用 tty7 procs %83:输出按深度缩进,在前台进程旁标上 *,然后列出这些进程正在监听的端口。不过,这并不是检查编码 Agent 的方法:对于其中运行着繁忙 Agent 的窗格,procs 会报告 nothing running in this pane,因此将其理解为“工作进程已退出”是错误的。要查询这些 Agent,请使用 tty7 agents。

将工作交给另一个 Agent

一个窗格可以容纳另一个编码 Agent,上面提到的每个基本功能都适用, 此外还有一项只有 Agent 才有的功能:状态钩子会报告 working / waiting / done,因此 tty7 wait 可以等待 Agent,而不是等待它的进程树。

委派工作有一套操作指南——references/delegation.md。启动工作 Agent 前请先阅读。 其中涵盖了整个流程:为工作 Agent 提供独立的 git 工作树和工作区,在提示词中通过交付约定移交任务,确认命令确实已启动,跟进各个状态,从 git 中收集结果,同时启动多个工作 Agent,以及清理工作环境。

即使不看其他内容,也请牢记其中的四条规则:

  • 使用交互模式,绝不使用 -p。 claude -p 不会绘制 TUI:窗格会保持 空白,capture --plain 不会返回任何内容,用户看到的是一个空矩形,而且会话在一轮后结束,无法继续交互。请将任务作为参数传给交互式命令。
  • 会写入文件的工作 Agent 必须使用独立的 git 工作树。 两个 Agent 共用一个检出目录会互相覆盖,并影响用户的工作树。
  • 从 git 中收集结果,而不是从屏幕上收集。 告诉工作 Agent 提交更改; 然后查看差异。屏幕有边界,顶部内容会消失。
  • 向新窗格发送内容后,确认命令已离开提示符——见上文的回车键被吞检查。

查看状态

tty7 ls                    # every workspace: tabs, panes, who's attached
tty7 ws tree api           # one workspace as a tree — tabs, splits, panes, cwds
tty7 pane ls               # panes with their workspace, tab, cwd, live flag
tty7 pane ls --all         # + orphans: panes the server runs that no workspace holds
tty7 agents                # every coding agent on the machine and its status
tty7 status                # server pid, uptime, pane count, build, socket
tty7 machine ls            # this machine plus any linked remotes
tty7 events                # stream server events, one per line, until interrupted

值得了解一下 tty7 agents:它会报告每个运行已识别编码 Agent 的窗格状态:idle / working / waiting / done,并显示 Agent 自己的消息。如果你也是其中之一,你也会出现在该列表中。如果它发现某个 Agent 正在运行,但缺少状态钩子或状态钩子已过时,也会输出诊断信息——即 JSON 中的 diagnostics 字段,这可以解释为何某个 Agent 看起来像是卡住了。

为这些命令中的任意一个添加 --json,即可解析输出,而不是靠目视查看。成功时,-q 会抑制输出,但不会抑制错误。

不要破坏用户的会话

此机器上的窗格属于用户的真实工作,其中有些窗格里还有正在执行任务的其他编码 Agent。凡是你没有创建的内容,都应视为只读:

  • 绝不要对你未打开的窗格执行 send 或 exec。 向另一个 Agent 的窗格发送按键,或向用户正在输入的 shell 发送按键,都会打断当时正在进行的操作。操作窗格前先检查 tty7 agents。使用 --key 时尤其要小心:一个误发的 C-c 就会终止别人的工作。
  • 绝不要对你未创建的内容执行 pane close / tab close / ws rm。
  • 绝不要执行 pane close --orphans。 它会关闭机器上所有被遗弃的窗格,而被遗弃的窗格仍可能在运行真实命令。清理工具是给用户用的;告诉用户如何使用,不要擅自操作。
  • 绝不要执行 server stop 或 server restart。 服务器停止后,机器上的所有窗格都会关闭,包括你自己的。如果服务器确实似乎卡住了,请告知用户并让用户决定。
  • 清理你创建的内容。 临时窗格用完后执行 tty7 pane close %83;它可以一次接收多个 ID。ws rm 会断开工作区中所有窗格,因此只需移除临时工作区即可。真正可能遗留的是被中断的 tty7 run——对应窗格仍在运行,却没有任何引用它,并会显示在 tty7 pane ls --all 的结果中。

远程机器

-m <machine> 会通过本地服务器已有的链路路由任意命令:

tty7 -m devbox ls
tty7 -m devbox run -- cargo test

名称可以是完整的链路键(me@devbox:22),也可以只是主机名。CLI 不会建立新连接——如果链路已断开,或它属于跳板/代理链,CLI 会说明情况;此时应将问题交还用户,由用户从 GUI 连接。

尚未接入的功能

ws stop、machine connect 和 machine disconnect 会退出并显示尚未实现的消息。不要围绕它们制定计划。

参考文档

  • references/delegation.md — 委派操作指南:工作树、交接、看护、收集、扇出和清理。每当有另一个 Agent 即将开始工作时,都要阅读此文档。
  • references/commands.md — 一张表列出所有动词、子命令和标志,以及每项命令输出的 JSON 格式。需要使用上文未列出的动词,或准备解析 --json 输出并想了解字段名称时,请阅读此文档。

评论

支持 Markdown