見出し画像

Codexの確認画面でEnterを自動送信するAppleScriptを作りました。現時点の最終版


CodexをTerminalで使っていると、ときどき確認画面で止まります。

内容を確認してEnterを押せば進めるのですが、長めの処理を任せているときは、ちょうど席を外しているタイミングで止まってしまうことがあります。

そこで、Codexの確認画面だけを検出して、Terminalを前面に出したうえでEnterを送るAppleScriptを作りました。

最初はもっと単純に「特定の文字列が出たらEnterを押す」だけのスクリプトにしていました。ただ、それだと別の場面で誤操作する可能性があります。

そのため最終的には、以下のような形にしました。

  • Terminalの全ウィンドウを監視する

  • 各ウィンドウの現在選択中タブだけを見る

  • 表示内容の末尾1,200文字だけを判定対象にする

  • Codexの確認画面に特有の文言がそろった場合だけEnterを送る

  • 同じ確認画面に対しては、3秒以内に連打しない

  • 対象ウィンドウを前面に出してから入力する

この記事では、現時点で使っている最終版を残しておきます。

1. 何を自動化しているのか

このスクリプトが対象にしているのは、Codexの操作確認画面です。

たとえば、以下のような選択肢と確認文が画面上に出ているときだけ、承認候補として扱います。

  • Yes, proceed (y)

  • Yes, and don't ask again for commands

  • Press enter to confirm

単に「Yes」という文字があるだけでは動かず、選択肢と確認メッセージの両方が検出された場合だけEnterを送るようにしています。

もちろん、これはコマンドの内容を安全と判断する仕組みではありません。あらかじめCodexに任せる作業内容を確認したうえで、「この確認は自動で通してよい」と判断できる場面だけで使うためのものです。

2. 先に書いておきたいこと

この内容は、詳しい方から見ると「わざわざ記事にするほどでもない」と感じるかもしれません。

また、このスクリプトは表示された確認内容を理解して、安全性を判断するものではありません。Codexに任せる作業をあらかじめ確認したうえで、表示された確認画面を通過させているだけです。

そのため、コマンドの内容を1つずつ確認したい方や、安全性を厳密に管理したい方には、あまり参考にならないと思います。

本職でエンジニアをされている方や、業務環境、チーム開発、本番環境に関わる作業では、むしろやらない方がよい、あるいはやってはいけない内容かもしれません。

あくまで個人の開発環境で、作業内容を把握したうえでCodexに長めの処理を任せるとき、「確認のたびに席へ戻る手間を少し減らす」ために作ったものです。

この前提で問題なければ、以下が現時点の最終版です。

3. 現時点の最終版

property lastHandledWindowID : ""
property lastHandledTime : 0

on run
	set lastHandledWindowID to ""
	set lastHandledTime to 0
	
	log "Codex auto-enter monitor started"
	
	repeat
		try
			tell application "Terminal"
				set terminalWindows to every window
			end tell
		on error errMsg number errNum
			log "ERROR: Window list failed [" & errNum & "] " & errMsg
			set terminalWindows to {}
		end try
		
		repeat with targetWindow in terminalWindows
			try
				tell application "Terminal"
					set targetWindowID to (id of targetWindow) as text
					
					-- 対象ウィンドウで現在選択中のタブの表示内容を取得する
					set terminalText to (contents of selected tab of targetWindow) as text
				end tell
				
				if terminalText is not "" then
					set textLength to length of terminalText
					
					-- 末尾1200文字だけを判定対象にする
					if textLength > 1200 then
						set recentText to text (textLength - 1199) thru textLength of terminalText
					else
						set recentText to terminalText
					end if
					
					set hasProceedOption to false
					set hasConfirmMessage to false
					set recentLines to paragraphs of recentText
					
					repeat with oneLine in recentLines
						set lineText to oneLine as text
						
						-- A または B が表示されたら承認候補とみなす
						if (lineText contains "Yes, proceed (y)") or (lineText contains "Yes, and don't ask again for commands") then
							set hasProceedOption to true
						end if
						
						-- Codex の確認画面であることも確認する
						if lineText contains "Press enter to confirm" then
							set hasConfirmMessage to true
						end if
					end repeat
					
					if hasProceedOption and hasConfirmMessage then
						set secondsSinceLastEnter to 9999
						
						if targetWindowID is lastHandledWindowID then
							set secondsSinceLastEnter to (current date) - lastHandledTime
						end if
						
						-- 初回は即時実行。同じ確認画面が残る場合のみ3秒後に再試行する
						if secondsSinceLastEnter > 3 then
							log "Approval prompt found in Terminal window ID: " & targetWindowID
							
							tell application "Terminal"
								activate
								
								-- 対象ウィンドウを最前面に移動する
								try
									set index of targetWindow to 1
								on error errMsg number errNum
									log "ERROR: Window fronting failed [" & errNum & "] " & errMsg
								end try
							end tell
							
							-- 前面化とCodexの入力受付を待つ
							delay 1.0
							
							tell application "System Events"
								tell process "Terminal"
									set frontmost to true
									key code 36
								end tell
							end tell
							
							log "Return sent to Terminal window ID: " & targetWindowID
							
							set lastHandledWindowID to targetWindowID
							set lastHandledTime to current date
							
							-- 1件処理したら残りのウィンドウは次回の監視周期で確認する
							exit repeat
						end if
					end if
				end if
				
			on error errMsg number errNum
				log "ERROR: Window scan failed [" & errNum & "] " & errMsg
			end try
		end repeat
		
		delay 0.5
	end repeat
end run

4. 入れている安全策

確認画面らしい文言がそろうまで動かない

Yes, proceed (y) だけでは実行しません。

Press enter to confirm も同時に検出できた場合だけ、Codexの確認画面として扱います。

確認画面らしい文言が複数そろっていることを条件にすることで、別のログや通常の操作画面でEnterを送る可能性を減らしています。

画面全体ではなく末尾だけを見る

Terminalの表示内容すべてを解析すると、過去ログに残った文言まで拾ってしまう可能性があります。

そこで、判定対象は末尾1,200文字に絞っています。これなら、現在画面に出ている直近の確認画面を見やすくなります。

同じ画面への連打を防ぐ

確認画面が消えるまで少し時間がかかる場合もあるため、同じウィンドウに対しては3秒以内の再入力を抑制しています。

初回はすぐにEnterを送りますが、同じ確認画面が残っている場合だけ、少なくとも3秒待ってから再試行します。

対象のTerminalを前面に出してから入力する

AppleScriptからキー入力を送る場合、意図しないアプリに入力されるのが一番困ります。

そのため、対象のTerminalウィンドウを先頭に移動し、少し待ってからSystem Events経由でReturnキーを送るようにしました。

複数のTerminalウィンドウを開いているときでも、検出したウィンドウに対して入力するための処理です。

5. 使うときの注意点

このスクリプトは便利ですが、何でも自動承認してよいわけではありません。

特に、次のような場面では止めておいた方がよさそうです。

  • 削除や上書きなど、取り消しにくい操作をCodexに任せるとき

  • 実行内容をまだ自分で確認したいとき

  • TerminalでCodex以外の作業も並行しているとき

  • 複数の重要なTerminalウィンドウを開いているとき

自分の場合は、作業内容を最初に確認したうえで、長時間のファイル整理や実装作業など、承認のたびに止まりたくない場面で使う想定です。

「確認を自動化する」ためのものではありますが、最初に任せる内容を確認することまでは自動化しない方がよいと思っています。

6. おわりに

最初は「Enterを送るだけ」の小さな自動化でした。

ただ、実際に使うことを考えると、どの画面を対象にするのか、過去ログを拾わないか、連打しないか、どのTerminalに入力されるかまで考える必要がありました。

結果として、数十行のスクリプトではありますが、自分の使い方に合わせた監視ツールになったと思います。

Codexに長めの作業を任せることが増えてきたので、こういう小さな自動化も少しずつ整えていきたいです。

いいなと思ったら応援しよう!