okayurisotto.net

私が好きでやったことが他の人のためにもなったらお得かも!

Gemini CLIがFirefoxで認証URLを開けない原因を調べた

公開日:
最終更新日:

背景

Gemini CLIは初回起動時、認証URLをWebブラウザで開こうとします。しかし残念ながら私の環境では、URLが正常に開かれません。何度試しても、既定のWebブラウザとして設定されたFirefoxが、次のようなメッセージの書かれたウィンドウを表示して起動しないのです。

プロファイルが見つかりません
あなたの Firefox プロファイルを読み込めませんでした。プロファイルが存在しないかアクセスできません。

一般的にCLIアプリケーションがURLを既定のWebブラウザで開かせようとする場合には、標準出力にもそのURLを表示することで、コピーアンドペーストによる手動での遷移ができるようにしておくものだと思うのですが、残念ながらGemini CLIはそのような設計にはなっていません。

当初私はこの不具合について、「WindowsかFirefoxのバグだろう」と考えていましたが、しっかりとはデバッグしていませんでした。先日、重い腰を上げてデバッグに取り組んだところ、なかなか根が深そうな問題を見つけたため、ここに記事としてまとめておきます。

TL;DR

  • 原因:BusyBox64u AshがUSERPROFILE環境変数中のバックスラッシュをスラッシュに変換していた
  • 結果:Firefoxがユーザープロファイルを見つけられず起動に失敗する
  • 対処:Git Bashなど、環境変数を改変しないシェルを使用する

環境

まずは不具合の発生する私の環境について説明します。

  1. OSとしてWindowsを使っています。
  2. 既定のWebブラウザはFirefoxです。
  3. ターミナルエミュレータとしてAlacrittyを使っています。
  4. シェルとしてBusyBox64uのAshを使っています。
  5. 普段はBusyBox64u Ashから起動したWSL2を使っています。ディストリビューションはUbuntuです。
  6. WSL2 Ubuntu上ではzshを使っています。
  7. Node.jsはmise-en-placeによりインストールされています。

(mise-en-placeは、mise.toml設定ファイルの内容に基づいてPATH環境変数を切り替えることで、同じツールの異なるバージョンの使い分けを実現するだけのものです。)

はてさて、どこが問題でしょうか?

コードを読む

私は常々、こういった不具合調査において実は一番手っ取り早いのは、コードを読むことだと考えています。この状況では、Gemini CLIのコードです。

Gemini CLIはnpmにて公開されている、Node.jsで動くアプリケーションです。そのコードは以下のリポジトリで公開されています。

Node.jsでの開発では、package.jsonというファイルに依存関係が記述されます。URLを既定のWebブラウザで開く処理をGemini CLIが自作しているとはあまり考えられなかったため、まずはそれっぽい依存関係を探します。

Gemini CLIの開発はモノレポで行われているようです。モノレポとは、1つのリポジトリで複数のパッケージを開発するというスタイルで、リポジトリ内で、あるパッケージから別のパッケージへ依存することで、アプリケーション全体の結合度を下げています。どうやらGemini CLIの中でもCLIツールとしてのロジックは、/packages/cliで開発されているようです。

/packages/cli/package.jsonを見てみると……openというそれっぽい依存が見つかりました。

$ pnpm info open

open@10.2.0 | MIT | deps: 4 | versions: 51
Open stuff like URLs, files, executables. Cross-platform.
https://github.com/sindresorhus/open#readme

やはりすでにあるパッケージを使って実装されているようです。この時点で、Gemini CLIには非がないことがわかります。(それはそれとしてURLを標準出力してくれたらうれしいのですが……。)

さて、今度はopenライブラリを読んでいきましょう。

このライブラリは、オリジナルのnode-openにあったいくつかの問題を修正した、アクティブにメンテナンスされているライブラリであることが売りなようです。ソースコードは、TypeScriptやビルドツールなどを使わないシンプルなindex.jsファイル直書き形式です。

そしてざっくりと読んで見たところ、どうやらWindows環境では、wsl-utilsというまた別のパッケージが提供するpowerShellPath関数を呼び出すことでPowerShellを探し、node:process(Node.jsの標準ライブラリ)が提供するexecでそれを起動、StartStart-Processを呼び出すことでWebブラウザを起動しているようでした。

つまりこの時点で、プロセスは、

動かない:

Alacritty
 └─ BusyBox64u Ash
     └─ WSL2 Ubuntu (zsh)
         └─ Node.js
             └─ PowerShell
                 └─ Firefox

といった入れ子構造になっていることがわかります。

ちなみにここでいうPowerShellとは、pwsh.exe(PowerShell Core)ではなく、C:\Windows\System32\WindowsPowerShellの方のpowershell.exeです。ただし、今回の不具合においてこの区別は重要ではありません。

動作検証

まず、WSL2 Ubuntuから起動したPowerShellからStart-Process Firefoxを試してみたところ、Firefoxは起動に失敗しました。とりあえずGemini CLIやopenを介さず手動でも再現することがわかり一安心です。

動かない:

Alacritty
 └─ BusyBox64u Ash
     └─ WSL2 Ubuntu (zsh)
         └─ PowerShell
             └─ Firefox

次に、Alacrittyから直接PowerShellを起動するよう設定した上で、上記PowerShellコマンドが実行できるかを試してみたところ、Firefoxは正常に起動しました。この時点で、インストールされたFirefoxが何か致命的に壊れてしまっているわけではない(再インストールで解決するようなものではない)可能性が高いということがわかります。

動く:

Alacritty
 └─ PowerShell
     └─ Firefox

そして、BusyBox64uのAshから起動したPowerShellから同様のコマンドを試してみたところ……Firefoxは起動に失敗しました

動かない:

Alacritty
 └─ BusyBox64u Ash
     └─ PowerShell
         └─ Firefox

BusyBox64u Ashが間に挟まると起動しないようだ、ということがわかります。……しかし、Ashが挟まったからといって何が変わると言うのでしょうか?

また、次の状況でも起動に失敗しました。

動かない:

Alacritty
 └─ BusyBox64u Ash
     └─ Firefox

もはやここまでくると、どうしてGemini CLIを試してみるまでこの不具合を踏んでいなかったのか不思議になってきます。

「どうせ環境変数が足りないとかでしょ〜?」という直感に基づきデバッグしてみたところ、一部の環境変数の値の内容に違いがあることがわかりました。特に、Write-Output $env:HOMEWrite-Output $env:USERPROFILEの結果で、次のような違いが見られました。

-C:\Users\okayurisotto
+C:/Users/okayurisotto

どうやらBusyBox64u Ashでは、環境変数の値におけるパス区切り文字のバックスラッシュがスラッシュになっているようです。ちなみにFirefoxのプロファイルは普通、C:\Users\<username>\AppDataの下に置かれます。……原因これでは?

Ashのように環境変数を書き換えた環境をバッチファイルでも作って試してみると……。

set USERPROFILE=C:/Users/okayurisotto
echo %USERPROFILE%
"C:\Program Files\Mozilla Firefox\firefox.exe"
pause

プロファイルが見つかりません
あなたの Firefox プロファイルを読み込めませんでした。プロファイルが存在しないかアクセスできません。

原因これでしょ!

対処法とまとめ

Git BashはBusyBox64u Ashとは違い、環境変数のパス区切り文字を書き換えないため、BusyBox64u AshをやめてGit Bashを使うようにすることで解決しました。……解決と言っていいのかわかりませんが。

ちなみに、Microsoft Edgeはパス区切り文字がスラッシュであっても起動します。Google Chromeも同じChromiumであるためか同様に起動します。とはいえ流石に、Firefoxに非があるとは言えない状況だと思います。$USERPROFILEのバックスラッシュがスラッシュに書き換えられている状況は、流石に特殊すぎるでしょうから。

ちなみに、BusyBox64uに限らず、BusyBox64やBusyBoxでもバックスラッシュをスラッシュに書き換える挙動が確認できました。元々は、Linuxに似た使い心地の軽量な環境が欲しくて導入したBusyBoxでしたが……なかなかつらいです。

Windows、めんどい……。