headless-terminal について
シェルセッションをプログラムから制御する、ヘッドレス端末インターフェースの実装を支援するスキルです。プロセス管理、入出力処理、ライブラリ選択、例外ケースのテストを扱います。
主な機能
- 01インターフェースのメソッドと動作の確認
- 02pexpect、pty、subprocess の選択
- 03シェルプロセスのライフサイクル管理
- 04入出力とシグナルの処理
- 05タイムアウト、文字コード、起動設定のテスト
活用シーン
- 01プログラムから制御するシェルセッションの実装
- 02対話入力が必要なコマンドの実行
- 03端末出力の取得とキャンセル処理
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ letta-ai/ skills --skill headless-terminalインストール後、Claude Code で/headless-terminalを入力して読み込まれたか確認します。
詳細
ヘッドレスターミナルの実装
概要
このスキルでは、可視のターミナル UI を使わずにシェルセッションを制御する、プログラムによるラッパーであるヘッドレスターミナルインターフェースの実装方法を説明します。通常、このような実装では、シェルプロセスの起動、入力(キー入力やコマンド)の送信、出力の取得を行います。
アプローチ
ステップ 1:インターフェースの契約を理解する
実装を始める前に、実装対象のインターフェースを十分に読み、理解してください。
- 必須のメソッドとシグネチャをすべて特定します
- 戻り値の型と想定される動作を確認します
- オプションのメソッドや機能がないか確認します
- 想定される動作を明らかにする既存の実装やテストを探します
ステップ 2:基盤となるライブラリを選択する
Python でターミナルをエミュレートする際によく使われるライブラリ:
| ライブラリ | 最適な用途 | トレードオフ |
|---|---|---|
pexpect | 対話型ターミナルのエミュレーション、パターンマッチング | 高水準 API。expect/send パターンに適しています |
pty | 低水準の疑似端末制御 | 制御性は高いものの、定型コードが増えます |
subprocess | 単純な非対話型コマンド | 本格的なターミナルエミュレーションには制限があります |
ドキュメントに記載する選定基準:
- 対話型の入力(パスワードやプロンプト)が必要ですか? →
pexpect - 低水準のターミナル制御が必要ですか? →
pty - 非対話型のコマンド実行のみですか? →
subprocessで十分な場合があります
将来の保守性を考慮し、理由とともに選択を明記してください。
ステップ 3:シェルの設定に対応する
シェルプロセスを起動するときは、次の設定項目を検討してください。
対話モード(-i フラグ):
- 起動ファイル(
.bashrc、.bash_profile)が読み込まれるようにします - シグナル処理の動作に影響します
- テストで起動ファイルの読み込みを検証する場合に必要です
エコーの動作:
- pexpect で
echo=Falseを指定すると、入力が出力に表示されなくなります - ユースケースで入力のエコー表示が必要かどうかを検討してください
ターミナルのサイズ:
- デフォルトの
(24, 80)は標準的なターミナルサイズです - ターミナル幅を検出するコマンドの出力形式に影響することがあります
- サイズを指定する理由を記載してください
ステップ 4:主要な機能を実装する
インターフェースで求められていることを正確に実装してください。
- プロセスのライフサイクル管理 - 起動、生存確認、終了
- 入力処理 - キー入力の送信、特殊キー(Ctrl+C など)への対応
- 出力の取得 - 利用可能な出力の読み取り、バッファリングへの対応
- リソースのクリーンアップ - 適切な終了、コンテキストマネージャーのサポート
ステップ 5:エッジケースに対応する
次の状況に明示的に対応してください。
| エッジケース | 対応方針 |
|---|---|
| シェルが予期せず終了する | 操作の前にプロセスの生存を確認します |
| 実行時間の長いコマンド | 設定可能なタイムアウト、バックグラウンド実行のサポート |
| 非 ASCII 文字 | 明示的なエンコーディング処理(通常は UTF-8) |
| 競合状態 | 送信と読み取りの間に適切な遅延を設けます |
| コマンドのキャンセル | 適切なシグナル処理(Ctrl+C に対する SIGINT) |
検証方法
テストのアプローチ
各機能に焦点を当てたテストを作成します。
- 基本機能 - インポート、インスタンス化
- 非対話型コマンド - 単純なコマンドの実行と出力
- 対話型コマンド - 入力を必要とするコマンド
- シグナル処理 - Ctrl+C によるキャンセル
- シェルの状態 - 変数の保持、環境
- 起動時の設定 - 起動ファイルが読み込まれることの検証
- バックグラウンド実行 - 実行時間の長いコマンドへの対応
検証のガイドライン
- テストスイートを実行し、すべての機能を検証します
- テストに合格した後に、重複する手動検証を行わないでください
- 包括的なテストファイルが 1 つある場合は、検証用スクリプトを別途作成せず、そのファイルを使用してください
よくある落とし穴
スコープ管理
- 必要なものだけを実装する - 追加のユーティリティメソッドなど、依頼されていない機能を加えないでください
- 追加メソッドが役立つと思われる場合は、その旨を記載しますが、依頼されない限り実装しないでください
- コンテキストマネージャーのサポートは期待されることが多いですが、インターフェースに含まれているか確認してください
効率性
- 検索を重複させない - クラスを検索する場合は、対象を絞った検索を一度行えば十分です
- 検証を重複させない - テストに合格した場合、追加の手動確認は不要です
- 明示的に依頼されない限り、サンプルファイルを作成しないでください
ドキュメントの不足
文書化されるべきですが、見落とされることの多い一般的な判断事項:
- 代替手段ではなく、選択したライブラリを使う理由
- 特定のシェルフラグを使用する理由
- 特定のデフォルト値を選んだ理由
- スレッドセーフ性に関する考慮事項(またはスレッドセーフではないことの明示)
エラー処理
以下の処理について検討し、文書化してください。
- 無効なキー入力シーケンス
- ターミナルプロセスの終了
- タイムアウトの状況
- 権限の問題
実装チェックリスト
実装を完了とする前に、以下を確認してください。
- すべてのインターフェースメソッドが実装されている
- ライブラリの選択理由が文書化されている
- 設定に関する判断に根拠が示されている
- エッジケースが明示的に処理されているか、対象外として文書化されている
- テストですべての必須機能がカバーされている
- 依頼されていない機能が追加されていない
- リソースのクリーンアップが適切に実装されている
コメント
Markdown 対応