关于 interminai
interminai 是供 Agent 使用的交互式终端代理,可运行需要输入、菜单或全屏界面的命令行程序。它通过会话套接字发送输入、读取屏幕与回滚内容,并提供状态检查和等待功能。
主要功能
- 01启动交互式命令行程序
- 02通过套接字发送输入
- 03读取屏幕与回滚内容
- 04检查状态并等待输出或条件
- 05调整终端大小与回滚缓冲区
适用场景
- 01执行 vim 或交互式 Git 操作
- 02处理菜单和全屏终端界面
- 03监督 CLI LLM 的运行状态
- 04等待终端提示或任务完成
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mstsirkin/ interminai --skill interminai安装后在 Claude Code 中输入/interminai确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples.mdreference.mdscripts/.gitkeep详细介绍
🌀 面向 AI 的交互式终端(interminai)
作者:Michael S. Tsirkin [email protected]
交互式 CLI 应用的终端代理。详情请参阅 examples.md 和 reference.md。
适用场景
用于交互式命令,例如需要等待输入、显示菜单/提示,或使用全屏界面(vim、git rebase -i、htop、apt、w3m)的命令。
如果遇到类似以下错误,也请使用:“Warning: Output is not to a terminal” 或 “Warning: Input is not from a terminal”。
不要用于运行后立即退出的简单命令——请改用 Shell。
快速开始
# 1. Start session (prints socket path to use in subsequent commands)
./scripts/interminai start -- vim /tmp/test.txt
# Output:
# PID: 12345
# Socket: /tmp/interminai-aBc123/socket
# Auto-generated: true
# 2. Use the socket path shown above for all subsequent commands
./scripts/interminai input --socket /tmp/interminai-aBc123/socket --text ':wq\r'
# 3. Check screen
./scripts/interminai output --socket /tmp/interminai-aBc123/socket
# 4. Clean up (always!)
./scripts/interminai stop --socket /tmp/interminai-aBc123/socket
只需从 start 的输出中读取套接字路径并直接使用,无需解析到变量中。
基本命令
start [--scrollback N] -- COMMAND- 启动应用(在标准输出中打印套接字路径,滚动缓冲区默认值为 10000)input --socket PATH --text 'text'- 发送输入(转义字符:\r\n\e\t\xHH,另请参阅“按 Enter 键”)output --socket PATH- 获取屏幕内容和滚动缓冲区(添加--cursor print可显示光标,使用--from N --to M指定范围)status --socket PATH- 检查运行状态、活动情况、尺寸和滚动缓冲区使用量status --socket PATH --quiet- 检查是否仍在运行(退出码为 0)或已退出(退出码为 1,并打印退出码)wait --socket PATH- 等待活动(任何输出),并打印活动情况和退出状态wait --socket PATH --quiet- 等待进程退出(打印退出码)wait --socket PATH --line N- 等待第 N 行发生变化(从 1 开始计数)wait --socket PATH --line N --not-contains PATTERN- 等待第 N 行不再包含 PATTERNwait --socket PATH --line N --contains PATTERN- 等待第 N 行包含 PATTERNstop --socket PATH- 停止会话(同时清理自动生成的套接字)
关键最佳实践
- 使用自动生成的套接字:启动时不要指定
--socket,从输出中读取路径 - 始终清理:完成后运行
stop(会自动清理套接字) - 每次输入后检查输出——不要盲目地连续执行命令
- 添加延迟:输入后运行
sleep 0.2,以便程序处理 - 为 git rebase -i、git commit 等设置 GIT_EDITOR=vim
- 如果屏幕显示乱码:发送
\f(Ctrl+L)以重新绘制 - 绝不要使用 grep/sleep 循环轮询:使用
wait阻塞,直到内容发生变化。使用wait --line N --not-contains PATTERN等待忙碌指示消失。请参阅下文“等待 CLI 大模型进入空闲状态”。 - 输出有限制:无需通过管道传给 head/tail——输出始终只显示一屏,默认 25 行。
- 如果输出已滚出屏幕,请使用滚动缓冲区:先运行
output --from -100 --to 0查看最近 100 行滚动缓冲区。还需要更多内容?运行output --from -200 --to -100,以此类推。继续分块向前查找,直到找到所需内容。 - 大量输出时增大滚动缓冲区:如果命令会产生大量输出(例如
make、cargo build、git log),启动会话时使用--scrollback 50000或更大的值。
检查活动情况(推荐用于大模型)
使用 status 检查终端是否有新输出,而不会阻塞。如果你正在运行 Claude 或 Codex 等大模型,并想决定是获取新输出还是再多等一会儿,这会很有用。
./scripts/interminai status --socket /tmp/interminai-xxx/socket
# Output:
# Running: true
# Activity: true
高效轮询的模式:
# After sending input, check if there's activity before fetching output
./scripts/interminai input --socket $SOCK --text 'make build\r'
sleep 0.5
# Check activity without blocking
./scripts/interminai status --socket $SOCK
# If Activity: true, fetch output
# If Activity: false, wait longer or send more input
这样可以避免在没有任何变化时反复调用 output,节省上下文窗口空间并减少噪声。当收到 PTY 输出时,活动标记会被设置;调用 status 或 wait 后,该标记会被清除。
等待 CLI 大模型进入空闲状态(cursor-agent、codex 等)
监督 cursor-agent 之类的 CLI 大模型时,需要检测它们何时完成处理并等待输入。
各 CLI 大模型的忙碌/空闲指示:
| CLI | 忙碌模式 | 空闲模式 |
|---|---|---|
| cursor-agent | 输入行上显示 ctrl+c to stop | → Add a follow-up |
| codex | Working (Ns • esc to interrupt) | › 提示符 |
| gemini | Thinking... (esc to cancel, Ns) | 输入框中的 > |
| claude | ✶ <word>… (ctrl+c to interrupt · Ns) | ❯ 提示符 |
审批提示:
- cursor-agent:显示“Run this command?”对话框
- codex:显示命令并等待输入 y/n
- gemini:显示带有选项的“Allow execution of: ...”模态框
- claude:权限提示(除非使用 --dangerously-skip-permissions)
检测策略(按行等待):
- 找到包含输入提示符的行号(例如,包含
ctrl+c to stop的行) - 等待该行不再包含
ctrl+c to stop
示例:监督 cursor-agent
# Start cursor-agent
./scripts/interminai start --size 120x40 -- cursor-agent
# Output: Socket: /tmp/interminai-xxx/socket
SOCK=/tmp/interminai-xxx/socket
# Send a prompt
./scripts/interminai input --socket $SOCK --text 'Write hello world in Python'
sleep 0.1
./scripts/interminai input --socket $SOCK --text '\r'
# Show full screen with line numbers to find 'ctrl+c to stop'.
# IMPORTANT: always read the full colored output yourself - never pipe
# to grep/head or use --no-color when looking for line numbers.
# You must see the whole screen to tell a UI prompt from random text.
./scripts/interminai output --socket $SOCK -n
# Find the line number that has 'ctrl+c to stop' (the input prompt
# line during generation) and wait for it to change
timeout 120 ./scripts/interminai wait --socket $SOCK \
--line $INPUT_LINE --not-contains 'ctrl+c to stop'
# Now cursor-agent is idle (or showing approval prompt), check full screen.
# Look for 'Run this command?' or idle prompt yourself - do not grep.
./scripts/interminai output --socket $SOCK
# if you see 'Run this command?'
# Approval prompt - approve with 'y' or skip with 'n'
./scripts/interminai input --socket $SOCK --text 'y'
# otherwise - Idle - ready for next command
echo "cursor-agent is idle"
为什么按行检测? 生成期间,输入行的行号相对稳定。等待该特定行并手动检查输出变化,可以避免屏幕其他位置的模式匹配造成误判。
不要使用 grep/sleep 轮询循环来等待 CLI 大模型完成:
# BAD - wastes time and context window
for attempt in $(seq 1 60); do
sleep 10
interminai output --socket $SOCK --no-color | grep 'ctrl+c to stop' || break
done
改用 wait --line N --not-contains PATTERN,它会高效阻塞,直到条件满足,且没有轮询开销。
终端大小
默认终端大小为 80x24。如果屏幕上无法容纳足够的上下文,请在启动时使用 --size 或使用 resize 增大窗口。不要设置得过大,以免上下文中充斥过多输出。
# Start with larger terminal
./scripts/interminai start --size 80x256 -- COMMAND
# Or resize during session (use socket path from start output)
./scripts/interminai resize --socket /tmp/interminai-xxx/socket --size 80x256
Vim 导航技巧
精确指定 h/j/k/l 的移动次数至关重要——执行 dd 后的光标位置并不总是直观。建议使用:
:<number>- 直接跳转到指定行(:5\rdd)/<pattern>- 搜索文本(/goodbye\rdd)gg/G- 从已知位置定位--cursor print- 检查操作后的光标位置:%s/old/new/gc- 搜索并替换,逐项确认(每个匹配项输入y/n)
复杂编辑的快捷方式
对于复杂的多行编辑,也可以在 vim 外部编辑:
- 使用
output查看文件名 - 使用 Edit 工具直接修改文件
- 在 vim 中重新加载文件(
:e!\r),或直接退出(:q!\r)
这样可以避免处理大型或复杂修改时进行棘手的 vim 导航。
不过,如果本来就要使用 sed 编辑,那么在 vim 中使用 :%s/old/new/gc 更可靠、功能也更强大,因为它会逐项显示每处修改。
按 Enter:\n 与 \r
传统 Unix 应用接受 \n(LF)或 \r(CR)作为 Enter,因为内核 TTY 驱动会在启用 ICRNL 标志时(“cooked”模式下默认启用)将 CR 转换为 LF。不过,一些现代应用(尤其是基于 React/Ink 的 TUI,例如 cursor-agent)会以 raw 模式运行并禁用 ICRNL,因此只识别 \r。
最佳实践:按 Enter/提交时始终使用 \r。它在各种情况下都适用:
- 传统应用:内核会将
\r转换为\n(如果启用了 ICRNL) - raw 模式应用:会按预期直接接收
\r
只有在确实想在多行输入中添加换行符时才使用 \n(例如继续在新行输入但不提交)。
# Submit a command (use \r)
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'hello world\r'
# Multiline input (use \n for newlines, \r to submit)
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'line1\nline2\nline3\r'
需要按 Enter 的菜单提示
对于 git add -i/-p,显示的菜单并非交互式;按下 Enter 后操作才会生效。例如:
- Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]?
实际上,需要输入 y 后再按 Enter;发送 Enter 后操作才会生效。
如果你观察到某个工具等待过一次 Enter,就可以放心地认为它下次也会等待 Enter。
现代 TUI 应用(基于 Ink/React)
使用 React/Ink 构建的应用(如 cursor-agent)需要在输入文本和按 Enter 之间加入延迟。因为 React 的内部状态尚未就绪,在同一次输入调用中发送文本和 Enter 键不起作用。
关键发现:仅轮询输出是不够的。即使屏幕上已显示文本,React 的状态机也可能尚未就绪。必须加入时间延迟。
简单模式(推荐):
# Send text, wait, then send Enter
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'your prompt here'
sleep 0.1
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text '\r'
原因:100ms 的延迟让 React 的事件循环有时间处理输入并更新内部状态,然后再接收 Enter 键。
使用 debug 命令检查应用是否处于原始模式(没有 ICRNL 标志)。
长时间运行的 Shell 会话
可以创建一个 shell 终端会话并向其中传递命令。
提示:Sudo 会按 TTY 缓存凭据。每次 interminai start 都会创建一个新的 PTY,因此即使你刚在其他地方完成身份验证,sudo 仍会每次提示输入密码。使用长时间运行的 shell 会话,只需输入一次密码即可运行多条 sudo 命令。
GIT_EDITOR=vim ./scripts/interminai start -- bash
# Output shows: Socket: /tmp/interminai-xxx/socket
sleep 0.5
./scripts/interminai output --socket /tmp/interminai-xxx/socket
# ... send commands now, using the socket path from above ...
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'vim foo.txt\r'
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text ':wq\r'
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'vim bar.txt\r'
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text ':wq\r'
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text 'exit\r'
./scripts/interminai wait --socket /tmp/interminai-xxx/socket
Git 示例
GIT_EDITOR=vim ./scripts/interminai start -- git rebase -i HEAD~3
# Output shows: Socket: /tmp/interminai-xxx/socket
sleep 0.5
./scripts/interminai output --socket /tmp/interminai-xxx/socket
# ... edit with input commands, using the socket path from above ...
./scripts/interminai input --socket /tmp/interminai-xxx/socket --text ':wq\r'
./scripts/interminai wait --socket /tmp/interminai-xxx/socket
切勿使用 --no-color,除非要将输出通过管道传给 grep/head/tail。即使由大模型读取输出,也包括在内——颜色会显示给用户,并有助于区分屏幕上的 UI 元素、提示词和内容。
# Normal viewing - no --no-color flag:
./scripts/interminai output --socket /tmp/interminai-xxx/socket
# ONLY IF piping to grep/head/tail - add --no-color:
./scripts/interminai output --socket /tmp/interminai-xxx/socket --no-color | grep pattern
./scripts/interminai output --socket /tmp/interminai-xxx/socket --no-color | tail -5
完整的命令文档请参阅 reference.md。
密码输入
当命令提示输入密码时(sudo、ssh 等),不要尝试自行处理密码。请告知用户自行运行 interminai input --password:
./scripts/interminai start -- sudo apt update
# Output shows: Socket: /tmp/interminai-xxx/socket
sleep 0.5
./scripts/interminai output --socket /tmp/interminai-xxx/socket
# Shows: [sudo] password for user:
# IMPORTANT: Tell the user to run interminai input --password
echo "Password required. Please run: interminai input --socket /tmp/interminai-xxx/socket --password"
# User runs the command, types password, and it's sent to sudo
./scripts/interminai wait --socket /tmp/interminai-xxx/socket
--password 标志:
- 提示用户输入密码并按 Enter 提交(以
\r发送) - 在关闭回显的情况下读取输入(密码不会显示)