mcpField
I
interminai

interminai

github.com/mstsirkinAgent 工作流5649 次安装4 天前更新
代码仓库

关于 interminai

interminai 是供 Agent 使用的交互式终端代理,可运行需要输入、菜单或全屏界面的命令行程序。它通过会话套接字发送输入、读取屏幕与回滚内容,并提供状态检查和等待功能。

主要功能

  1. 01启动交互式命令行程序
  2. 02通过套接字发送输入
  3. 03读取屏幕与回滚内容
  4. 04检查状态并等待输出或条件
  5. 05调整终端大小与回滚缓冲区

适用场景

  1. 01执行 vim 或交互式 Git 操作
  2. 02处理菜单和全屏终端界面
  3. 03监督 CLI LLM 的运行状态
  4. 04等待终端提示或任务完成

安装

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

$npx skills add https://github.com/mstsirkin/interminai --skill interminai

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples.md
reference.md
scripts/
.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 行不再包含 PATTERN
  • wait --socket PATH --line N --contains PATTERN - 等待第 N 行包含 PATTERN
  • stop --socket PATH - 停止会话(同时清理自动生成的套接字)

关键最佳实践

  1. 使用自动生成的套接字:启动时不要指定 --socket,从输出中读取路径
  2. 始终清理:完成后运行 stop(会自动清理套接字)
  3. 每次输入后检查输出——不要盲目地连续执行命令
  4. 添加延迟:输入后运行 sleep 0.2,以便程序处理
  5. 为 git rebase -i、git commit 等设置 GIT_EDITOR=vim
  6. 如果屏幕显示乱码:发送 \f(Ctrl+L)以重新绘制
  7. 绝不要使用 grep/sleep 循环轮询:使用 wait 阻塞,直到内容发生变化。使用 wait --line N --not-contains PATTERN 等待忙碌指示消失。请参阅下文“等待 CLI 大模型进入空闲状态”。
  8. 输出有限制:无需通过管道传给 head/tail——输出始终只显示一屏,默认 25 行。
  9. 如果输出已滚出屏幕,请使用滚动缓冲区:先运行 output --from -100 --to 0 查看最近 100 行滚动缓冲区。还需要更多内容?运行 output --from -200 --to -100,以此类推。继续分块向前查找,直到找到所需内容。
  10. 大量输出时增大滚动缓冲区:如果命令会产生大量输出(例如 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
codexWorking (Ns • esc to interrupt)› 提示符
geminiThinking... (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)

检测策略(按行等待):

  1. 找到包含输入提示符的行号(例如,包含 ctrl+c to stop 的行)
  2. 等待该行不再包含 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 外部编辑:

  1. 使用 output 查看文件名
  2. 使用 Edit 工具直接修改文件
  3. 在 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 发送)
  • 在关闭回显的情况下读取输入(密码不会显示)

评论

支持 Markdown