mcpField
I
interminai

interminai

github.com/mstsirkinエージェントワークフロー5649 回インストール4 日前に更新
リポジトリ

interminai について

interminaiは、入力やメニュー、全画面表示を必要とするコマンドラインアプリ向けのインタラクティブなターミナルプロキシです。セッションソケットで入力を送り、画面やスクロールバックを読み取り、状態確認や条件待ちを行えます。

主な機能

  1. 01インタラクティブなコマンドラインアプリの起動
  2. 02セッションソケット経由の入力送信
  3. 03画面とスクロールバックの読み取り
  4. 04状態確認と出力・条件の待機
  5. 05ターミナルサイズとスクロールバック容量の変更

活用シーン

  1. 01vimや対話型Git操作の実行
  2. 02メニューや全画面ターミナルの操作
  3. 03CLI 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 - 何行目かを変更されるまで待ちます(行番号は 1 から始まります)
  • wait --socket PATH --line N --not-contains PATTERN - 何行目にも PATTERN が含まれなくなるまで待ちます
  • wait --socket PATH --line N --contains PATTERN - 何行目かに 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 LLM のアイドル状態を待つ」を参照してください。
  8. 出力には上限があります:head/tail にパイプする必要はありません。出力は常に画面 1 枚分のみです。デフォルトでは 25 行です。
  9. 出力がスクロールして見えなくなった場合は、スクロールバックを使用する:output --from -100 --to 0 で直近 100 行のスクロールバックを確認します。さらに必要ですか?output --from -200 --to -100 のように続けてください。必要な情報が見つかるまで、チャンク単位で遡って確認します。
  10. 出力が多い場合はスクロールバックを増やす:コマンドで大量の出力が予想される場合(例:make、cargo build、git log)、--scrollback 50000 以上を指定してセッションを開始してください。

アクティビティの確認(LLM に推奨)

ブロックせずに新しいターミナル出力があるか確認するには、status を使用してください。 Claude や Codex などの LLM を実行していて、新しい出力を取得するか、さらに待つかを判断したい場合に便利です。

./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 LLM がアイドル状態になるのを待つ(cursor-agent、codex など)

cursor-agent のような CLI LLM を監視する際は、処理が終わり、入力待ちになったことを検知する必要があります。

CLI LLM ごとのビジー/アイドル状態の表示:

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"

行単位で待機する理由:生成中も入力行の番号は比較的安定しています。その特定の行を待ち、変化を手動で確認することで、画面上のほかの場所にあるパターンとの誤一致を避けられます。

CLI LLM の処理完了を待つために、grep/sleep によるポーリングループを使用しないでください。

# 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 アプリは、Enter キーとして \n(LF)と \r(CR)のどちらも受け付けます。ICRNL フラグが有効な場合(「cooked」モードではデフォルト)、カーネルの TTY ドライバーが CR を LF に変換するためです。しかし、一部の最新アプリ(特に cursor-agent などの React/Ink ベースの TUI)は ICRNL を無効にした raw モードで動作し、\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 キーを待つことを確認できたら、次回も待つと考えて差し支えありません。

モダンな TUI アプリ(Ink/React ベース)

React/Ink で構築されたアプリ(cursor-agent など)では、テキストを入力してから Enter キーを押すまでに遅延が必要です。1 回の入力呼び出しでテキストと 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 の遅延によって、Enter キー入力を受け取る前に、React のイベントループが入力を処理し、内部状態を更新する時間が確保されます。

アプリが raw モード(ICRNL フラグなし)かどうかを確認するには、debug コマンドを使用します。

長時間実行するシェルセッション

シェルの中間ターミナルセッションを作成し、コマンドを渡すことができます。

ヒント:sudo は TTY ごとに認証情報をキャッシュします。interminai start を実行するたびに新しい PTY が作成されるため、別の場所で最近認証していても、毎回 sudo のプロンプトが表示されます。長時間実行するシェルセッションを使用すると、1 回のパスワード入力で複数の 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

grep/head/tail にパイプで渡す場合を除き、--no-color は絶対に使用しないでください。LLM が出力を読み取る場合も同様です。色はユーザーに表示され、画面上の 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 を使用します
  • エコーを無効にして入力を読み取ります(パスワードは表示されません)

コメント