デスクトップアプリ
各リリースには Docker イメージに加えて Electron デスクトップビルドが含まれます。macOS(Apple silicon と Intel)、Windows、Linux(x86_64 と arm64)に対応しています。
仕組み
デスクトップアプリは Electron ウィンドウと、コンソールのバックエンドで構成されます。ウィンドウに表示されるのは常にインストーラーに同梱されたこのコンソールであり、バックエンドはデータの取得元を決めるだけです。同じインストーラーに同梱されたゲートウェイか、あなたがすでに運用しているデプロイです。
- バックエンドが「このマシン」の場合、メインプロセスがゲートウェイ(Docker イメージと同じ Next.js standalone サーバー)を起動し、
/healthが応答するまで待ってからコンソール画面を開きます。 - ゲートウェイは
127.0.0.1のみで待ち受け、LAN には公開されません。 - バックエンドが「このマシン」の場合、既定ポートは
8001です。初回起動のダイアログ、メニューの「設定…」、または「設定 → デスクトップアプリ」から変更できます。デプロイを選んだ場合に尋ねるのはアドレスだけで、ポートは保存されている値のままです。ポートが確定している場合(ここで保存した、またはCODEBUDDY_DESKTOP_PORTで指定した)、使用中でもアプリは勝手に別のポートへ移動せず、どのポートを使うかを尋ねます。 - macOS ではウィンドウを閉じてもゲートウェイは動き続け、
/v1/*は利用可能なままです。アプリを終了すると停止します。 - ウィンドウとゲートウェイは常に 1 つだけです。アプリの再起動やメニューバーのアイコンは、すでに開いているウィンドウを前面に出すだけです。macOS では Dock アイコンも表示します。コンソールはほかのウィンドウと同じ 1 つのウィンドウなので、メニューバーのアイコンだけでなく Dock や Cmd+Tab からも戻れます。
- バックエンドがこのマシンの場合、サインインは不要です。コンソールはループバックで待ち受け、応答するのはアプリ自身のウィンドウだけです。ログインページも「セキュリティ」設定も表示されません。バックエンドがデプロイの場合はどちらも戻ってきます。後述を参照してください。
- コンソールはアプリ自身のウィンドウにだけ配信されます。シェルは起動時にトークンを作り、環境変数でゲートウェイへ、Cookie でウィンドウへ渡します。それを持たないリクエスト(ブラウザやスクリプト)には
127.0.0.1で 404 を返します。/v1/*と/healthは対象外です。ゲートウェイが本来提供するものだからです。
バックエンド
初回起動時にバックエンドを選ぶのは、このコンピュータ自身のダイアログです。ポートはローカルゲートウェイのものなので、「このマシン」を選んだときだけ同じダイアログで尋ねます。macOS では AppKit のダイアログ、Windows では WinForms のフォーム、Linux では zenity が描くものです。画面上にこのアプリが描くものはなく、外観もボタンも言語もデスクトップとコンソールのものになります。以後はメニューバーのアイコンのメニューから「設定…」で両方を変更できます。そのダイアログが答えのないまま閉じられた場合、アプリは終了します。ゲートウェイはこの選択が決めるものであり、誰も選んでいないものを起動するのは答えにはなりません。ダイアログを描けないコンピュータ(ヘッドレスなセッション)では、このアプリが描いたページではなく、そのコンピュータ自身のメッセージボックスでその旨を伝え、初回起動なら終了します。CODEBUDDY_DESKTOP_ASK=window はアプリ自身のウィンドウで尋ねます。テスト実行時のためのものです。ネイティブのダイアログはテストからはクリックできないからです。
- このマシン: インストーラーに同梱されたゲートウェイを起動し、データはこのマシンに置かれ、サインインも不要です。既定の選択肢です。
- すでに運用しているデプロイ:
http://またはhttps://のアドレスを指定します。アプリはコンソールを表示するために自分のゲートウェイを起動し、/admin-api/*と/v1/*だけをそのデプロイへ転送します。ウィンドウに出るのは常にこのアプリが同梱したコンソールであり、デプロイが返したページではありません。接続前に/healthを確認し、それが CodeBuddy2API のデプロイかどうかを確かめます。確認できない場合はウィンドウがどちらだったか(応答がなかったか、別のものが応答したか)を伝え、再試行・バックエンドの変更・ブラウザで開くことができます。サインインを求められる場合があり、その扱いはデプロイ側が行います。デスクトップアプリはパスワードを保存しません。 - オフラインのときやアドレスが違うときも、空のウィンドウは開きません。理由を伝える上記のウィンドウが開きます。
リモートのバックエンドを選ぶと、メニューの「バックエンド」行にはそのアドレスが表示されます。「アドレスをコピー」がコピーするのはローカルのコンソールのアドレスです。/v1/* は転送されるため、API のエンドポイントとしてもそのまま使えます。ポートはこのマシンのゲートウェイがコンソールを配信するものなので、バックエンドがどちらであっても設定から変更できます。
設定
メニューバーのアイコンのメニューにある「設定…」が開くのは、このコンピュータ自身のダイアログであり、中にあるのもこのコンピュータ自身のタブです。macOS では AppKit のタブビュー(AppKit が描く alert の中)、Windows では WinForms の TabControl です。どちらもそのコンピュータの他のダイアログが使うコントロールであり、外観もボタンも言語もデスクトップとコンソールのものになります。画面上にこのアプリが描くものはありません。Linux では zenity にタブのコントロールがないため、まず一覧からセクションを選び、選んだセクションを zenity のダイアログで尋ねます。説明だけのセクションは情報ダイアログとして表示します。
3 つのタブ:
- 一般: 初回起動が尋ねるのと同じ質問です。バックエンドが「このマシン」か「すでに運用しているデプロイ」か、そしてこのマシンのゲートウェイがコンソールを配信するポートです。前回の答えが使えなかった場合(アドレスが正しくないなど)は、その旨がこのタブの先頭に表示されます。
- データ: ローカルバックエンドではデータフォルダとデータベースファイルのパスを示し、その下にリンクを出します。クリックするとこのデスクトップのファイルマネージャーでそのフォルダが開き、ダイアログは閉じません。リモートバックエンドではデータはそのデプロイにあるため、このタブはその旨とデプロイのアドレスを示すだけです。
- このアプリについて: アプリのバージョン、使用中のバックエンド(デプロイの場合はそのバージョンも)、そしてプロジェクトのリポジトリへのリンクです。クリックするとブラウザーで開きます。このためメニューには GitHub の行がありません。
書き込まれるのは「保存」を押したときだけです。バックエンドやポートを変更するとゲートウェイが再起動し、ウィンドウは新しいアドレスへ移動します。キャンセルすれば何も変わりません。CODEBUDDY_DESKTOP_ASK=window ではアプリ自身のウィンドウで尋ねます。テスト実行時のためのものです。ネイティブのダイアログはテストからはクリックできないからです。
サインイン
デスクトップ版に管理者パスワードはありません。ゲートウェイは 127.0.0.1 のみで待ち受け、コンソールはアプリ自身のウィンドウにだけ応答するため、パスワードはあなた自身をコンソールから締め出すだけです。
管理者パスワードが必要なのは自分でホストする場合だけです。デスクトップアプリでは /admin-api/auth/setup は 404 を返します。
バックエンドがデプロイの場合、サインインページもパスワードもそのデプロイのものです。アプリにパスワードを入力すればサインインできます。パスワードはそのデプロイへ転送され、コンソールが保持するのはそれが発行したセッション cookie です。
一方、そのデプロイのパスキー(passkey)と、ブラウザやシステムがそのホスト用に保存したパスワードはアプリからは使えません。どちらもデプロイのアドレスに紐づくものであり、このコンソールは 127.0.0.1 から配信されているためです。ブラウザは現在のオリジンにしか資格情報を提示しませんし、デプロイに設定された rpId とも一致しません。サインインページは必ず失敗するボタンを出す代わりにその旨を表示し、デプロイのページへのリンクを出します。そのリンクを開くとブラウザでデプロイのページが開き、そこではパスキーも保存済みのパスワードも使えます。
デバイスコードでのサインイン
だからこそ、ブラウザーからサインインする方法も用意されています。バックエンドがデプロイの場合、メニューに「サインイン…」が並びます。アプリはそのデプロイに 2 つのコードを求めます。1 つはアプリが待つためのもの、もう 1 つはあなたに表示されるものです。そしてブラウザーでデプロイ自身のページを開きます。コードはすでに入力済みです。そこで、そのデプロイが求める方法(パスキー、ブラウザーに保存されたパスワード、あるいはその両方)でサインインしてコードを承認してください。アプリが自分でトークンを受け取ります。127.0.0.1 のウィンドウにパスワードを入力することは一度もありません。
待っているあいだ、メニューはその旨を表示し、2 つ目のコードは出しません。承認の有効期限は 10 分です。コードが期限切れになっても、それはその一度きりの機会が終わったというだけなので、もう一度サインインしてください。サインイン済みになるとメニューは「サインイン済み」と表示し、「サインアウト」を選べるようになります。これはこのマシンからトークンを忘れ、デプロイにも忘れるよう依頼します。
トークンは userData 内の設定ファイルの隣に保存され、アプリを実行しているユーザーだけが読めます。そして、それを発行したアドレスにのみ属します。アプリを別のデプロイに向けたら、最初からやり直しになります。そのデプロイへ転送されるすべてのリクエストがこのトークンを運ぶため、サインアウトするまでウィンドウはサインイン済みのままです。サインインを求めないデプロイには、誰も承認できないコードではなく、その旨がそのまま伝えられます。
メニューバーの状態表示
macOS ではメニューバーに状態アイコンが常駐し、アイコンの横に本日のトークン消費量(入力 / 出力、1 分ごとに更新)が表示されます。メニューには現在のバックエンドとアドレスが並び、コンソールを開く、アドレスをコピーする、「設定…」を開く、アプリを終了できます。Windows と Linux でもトレイに同じアイコンが表示され、状態と消費量はヒントに、クリックではコンソールを開きます。
メニューの文言はコンソールの表示言語に従います。
バージョンとアップデート
メニューの末尾にはデスクトップ版のバージョンが並び、バックエンドがあなたの運用しているデプロイの場合はそのバージョンも並びます(アプリと異なることがあります)。同梱のゲートウェイを使う場合、サーバーのバージョンは表示されません。そのゲートウェイがアプリそのものだからです。
「設定…」の「このアプリについて」タブにも同じバージョンと、プロジェクトのリポジトリへのリンクがあります。このためメニューには GitHub の行がありません。
同じメニューの「アップデートを確認…」は GitHub に最新リリースを問い合わせます。新しいものがあれば先に確認し、了承されてからこのコンピュータ向けのインストーラをダウンロードしてシステムに開かせます(macOS では dmg をマウント、Windows ではセットアップを実行、Linux では AppImage を開きます)。このコンピュータ向けのビルドがないリリースでは、リリースページを開いて自分で選べるようにします。アプリが背後で自分を置き換えることはありません。
ポート
ポートの変更は、初回起動のダイアログ、メニューの「設定…」の「一般」タブ、または「設定 → デスクトップアプリ」で行います。保存するとゲートウェイが再起動し、ウィンドウは新しいアドレスへ移動します。保存または指定済みのポートが勝手に別のポートへ置き換わることはありません。使用中の場合は、同じダイアログでどのポートを使うかを尋ねます。決着がつくまでメニューバーにはその使用中のポートが表示されます。まだ何も保存していないインストールでは、空いている次のポートへ移動します。すでに 8001 を使っているデプロイの隣でもそのまま使えるようにするためです。
保存したことがない状態であれば CODEBUDDY_DESKTOP_PORT も使えます。一度コンソールで保存すると、保存した値が環境変数より優先されます。
ストレージ
デスクトップアプリは SQLite 固定です。対象はこのマシンだけで、データベースを共有する別プロセスがないため、選ぶ余地がありません。CODEBUDDY_STORAGE_BACKEND、DATABASE_URL、CODEBUDDY_STORAGE_PG_URL は無視され、設定画面のストレージバックエンドは変更できない項目として表示されます。
初回起動時に暗号化キーを生成するため、認証情報とアクセスキーは暗号化されて保存されます。storage-encryption-key を削除すると、暗号化済みのデータは復元できなくなります。 これはセルフホスト時と同じ契約です。バックアップはデータベースとキーをセットで取得してください。
データの保存場所
データはインストール先ではなく Electron の userData ディレクトリに書き込まれます。
| パス | 内容 |
|---|---|
data/ | ファイルストレージのディレクトリ(既定では storage.sqlite) |
credentials/ | CodeBuddy の認証情報ファイル |
storage-encryption-key | 初回起動時に生成されるストレージ暗号化キー(権限 0600) |
desktop-settings.json | アプリ自身の設定(バックエンドとポート) |
desktop-device-token.json | 承認後にデプロイがこのアプリへ発行したトークン(権限 0600) |
署名について
リリースの macOS ビルドは署名と Apple の公証を済ませているため、dmg をダブルクリックすれば開けます。Windows では SmartScreen が表示されるので「実行」を選んでください。
macOS に「壊れているため開けません」と表示される場合は、アプリを Applications にコピーしてから次を実行してください。
xattr -cr /Applications/CodeBuddy2API.app