# 自己更新

> HTML: https://remote.ivjn.us/docs/ja/self-update/

Windows x64/arm64、Linux x64/arm64（glibc および静的 musl ビルド）、macOS Apple Silicon、FreeBSD/NetBSD x64/arm64 の CLI とスタンドアロン Agent は、公開サイトから自身の実行ファイルを更新できます。

```sh
remote-cli update self --check
remote-cli update self
remote-agent update self --check
remote-agent update self
```

| プラットフォーム | リリースアーカイブ | 単発の `remote-agent update self` 後の再起動 |
| --- | --- | --- |
| Windows x64 / arm64 | `remote-windows-x64.zip` / `remote-windows-arm64.zip` | スケジュールタスク `RemoteAgent`、次にプロセス再起動 |
| Linux glibc x64 / arm64 | `remote-linux-x64.tar.gz` / `remote-linux-arm64.tar.gz` | systemd のシステム／ユーザーユニット、OpenRC、次にプロセス再起動 |
| Linux musl x64 / arm64 | `remote-linux-musl-x64.tar.gz` / `remote-linux-musl-arm64.tar.gz` | Linux glibc と同じ |
| macOS Apple Silicon | `remote-macos-arm64.tar.gz` | LaunchAgent `us.ivjn.remote-agent` |
| FreeBSD / NetBSD x64 / arm64 | `remote-freebsd-*.tar.gz` / `remote-netbsd-*.tar.gz` | `remote-agent install --system` が登録した rc.d `remote_agent`。ない場合は手動で再起動 |

updater は実行中の実行ファイルの C ランタイムを維持します。musl ビルドは musl アーカイブのみ、glibc ビルドは glibc アーカイブのみをインストールします。OpenWrt は x64/arm64 でも opkg/apk を使います。そのパッケージにはアーカイブ updater が含まれず、`/etc/openwrt_release` があるホストで動く musl アーカイブも自己更新を拒否します。manifest にアーカイブが載っているプラットフォームだけが更新されます。対応前にビルドされたインストールは一度手動で置き換えてください。

アカウントへのログインやデバイス設定は不要です。

Agent 自体の初回インストール（バイナリ、非公開設定、OS 自動起動）には、Linux、macOS、Windows で `remote-agent install` / `remote-agent uninstall` を推奨します。[platforms.md](/docs/ja/platform-installation.md) を参照してください。このコマンドにネットワーク接続は不要で、ペアリングは別途行います。`install` を含むバイナリを一度配置した後は、`update self` または対応環境の自動更新でアップグレードできます。

`--check` はマニフェストの実行ファイル SHA-256 を比較し、アーカイブのダウンロードを省略します。実行ファイルのメタデータがない場合のみアーカイブを取得して検証します。同じバージョンの開発ビルドも識別でき、確認中にインストールは変更されません。インストール時はダウングレードを拒否し、バージョン、サイズ、ハッシュを検証します。

既定の取得元は `https://r2.ivjn.us`（`downloads/` を配信する R2 公開ドメイン）です。`--source https://your-mirror.example/releases` で、同じ `downloads/manifest.json` とアーカイブ構成を持つ信頼できるミラーを指定できます。GitHub Releases（[mbcc2006/remote-control releases](/#downloads)）でも同種のデスクトップアーカイブを**追加の**ダウンロード経路として公開しています。Web サイトの構成を置き換えるものではなく、`--source` で `downloads/manifest.json` を配信するミラーを指定しない限り、自己更新は引き続き `r2.ivjn.us` を使用します。HTTPS のみを受け付け、リダイレクトは拒否し、アカウントトークンは送信しません。現在の OS とアーキテクチャからアーカイブ名を選び、サイズと SHA-256 を HTTPS マニフェストと照合して、完全一致する実行ファイルのエントリーだけを展開します。デスクトップクライアントは、組み込みの Ed25519 公開鍵で `downloads/manifest.json.sig` を検証してからマニフェストを信頼します。署名の欠落、改ざん、未知の鍵は更新を拒否します。ミラーは署名済みマニフェストと署名ファイルを変更せず配信し、署名を必須とするクライアントの導入前に署名ファイルを公開してください。

インストール前に、新しい実行ファイルは時間制限付きの `--version` 検査に合格する必要があります。同じディレクトリの `.update.lock` ファイルで更新を直列化し、現在の実行ファイルを再検査して並行した置き換えを検出します。更新が変更するのは実行ファイルとその更新・バックアップファイルのみで、デバイス ID、認証情報、設定ファイルは保持します。

macOS では、ダウンロードした実行ファイルはバージョン検査の前に `codesign --verify --strict` にも合格する必要があります。置き換え時に公開済みの署名とバイト列を保持し、以後のハッシュ比較を安定させます。

以前の実行ファイルは `<executable>.previous` として保持します。必要なら Agent を停止し、このファイルを元の実行ファイルのパスに戻してください。Windows では読み込み中の実行ファイルをバックアップ名に変更してから代替ファイルをインストールします。インストール失敗時は元の名前に戻します。

`remote-agent update self` が成功すると（`--check` は除く）、updater は実行中の Agent を再起動して新しい実行ファイルを読み込ませようとします。Linux（glibc と musl）では `systemctl restart remote-agent`、`systemctl --user restart remote-agent`、`/etc/init.d/remote-agent` がある場合は `rc-service remote-agent restart`（OpenRC）の順に試し、どれも使えない場合は他の `remote-agent` デーモンを以前の引数で SIGTERM 再起動します。Windows（x64 と arm64）ではスケジュールタスク `RemoteAgent` を再起動し、プロセス単位のフォールバックもあります。FreeBSD/NetBSD では `remote-agent install --system` が入れた rc.d スクリプト `remote_agent restart` を実行し、ない場合は手動再起動が必要と表示します。更新しているプロセス自体がデーモン（引数が `update self` ではない）の場合、Unix では新しい実行ファイルを `exec`（スーパーバイザー向けに PID を維持）し、Windows では切り離した代替プロセスを起動します。`remote-cli update self` は Agent を再起動しません。状態行には systemd、OpenRC、rc.d、スケジュールタスク、新規プロセスのどれで再起動したか、または再起動できなかったか（更新自体は成功）が表示されます。インストール所有者の権限で実行してください。updater は権限を昇格しません。再起動時に記録するコマンドラインでは `--token` の値を伏せます。以前の Windows Agent がバックアップから動作中の場合は、再起動してから再度更新してください。

## 自動更新（デスクトップ Agent デーモン）

Agent デーモンの実行中（単発の `update self` 以外）は、同じ Web サイトのマニフェストを**定期的に確認**し、公開された `remote-agent` バイナリが異なる場合に更新します（ハッシュ比較）。既定の動作:

- 対応デスクトップビルド（Windows x64/arm64 / Linux x64/arm64 glibc と musl / macOS arm64 / FreeBSD と NetBSD x64/arm64）では**既定で有効**です。
- 環境変数 `REMOTE_AUTO_UPDATE=0`（`false` / `no` / `off` も可）、JSON 設定 `"auto_update": false`、CLI の `--auto-update false` で無効にできます。
- 起動約 90 秒後に初回確認し、その後は約 12 時間ごとに確認します（ハートビートごとではありません）。
- 進行状況を明確に記録し、更新 CDN にデバイストークンを送ることは**ありません**。
- OpenWrt（OpenWrt ホスト上の musl アーカイブを含む）はデスクトップ自動更新をスキップし、Android は独自の OTA を使います。Intel Mac や 32 ビット ARM などの未対応アーキテクチャはリリースアーカイブなしのエラーとなり、自動更新できません。

## リモートからの更新配信（オペレーター → デバイス）

通常のデバイスセッション権限（`OpenExec` と同じ ACL）を持つオペレーターは、オンラインのデバイスに更新の確認または適用を要求できます。

プロトコル（WebSocket JSON）:

- `OperatorUp::update_device` `{ session_id, device_id, check_only, source? }`
- Exchange → `DeviceDown::update_req`
- デバイス → `DeviceUp::update_status` / `OperatorDown::update_status` で進行状況を通知。`phase` は以下:
  `checking` | `downloading` | `applying` | `up_to_date` | `available` | `applied` | `error`

コンソール: デバイス詳細の **更新を確認** / **更新を配信**。

CLI（他のデバイスセッション操作と同じ形式）:

```sh
remote-cli device update <device_id> --check
remote-cli device update <device_id>
remote-cli device update <device_id> --source https://r2.ivjn.us
```

LAN 制御が有効な場合、`update_device` は他の `OperatorUp` open-* メッセージと同じ方法でマッピングされます。

OpenWrt など非対応の Agent は、誤った成果物をインストールせず、明確な `error` フェーズを返します。Windows arm64、Linux musl、macOS Apple Silicon、FreeBSD/NetBSD は Windows x64 や Linux glibc と同じデスクトップアーカイブの経路を使います。

## Android Agent OTA

Android Agent APK（Web サイトの `remote-agent-android.apk`）は、同じ HTTPS マニフェストから自己更新できます。

Agent の **設定 → 更新を確認** を開くと手動確認できます。確認時に APK をダウンロードして検証し、更新がある場合は、Android インストーラーを開く前に別途確認を求めます。

- APK をダウンロードして**バイト数と sha256** を検証し、インストール済みアプリと `versionCode` / パッケージ名を比較します（同じバージョンでもハッシュが違う再ビルドはインストールできる場合があります）。
- `PackageInstaller` でインストールします。アプリは `REQUEST_INSTALL_PACKAGES` を宣言しています。初回 OTA では、システム設定で Remote Agent の「不明なアプリのインストール」を許可し、表示されたシステムインストーラー画面で確認する必要がある場合があります。
- インストール開始時は `applied` ではなく、インストール保留メッセージを伴う `available` を返します。
  非公開のインストーラーコールバックがシステムの確認画面を開きます。同じ保留 APK に対する繰り返しの要求はセッションを再利用し、失敗したものや古くなった自己更新セッションは破棄します。
  Agent の再接続後に、インストール済みバージョンとハッシュを確認してください。
- `AgentService` の実行中は同様の間隔で自動確認します。
- リモートの `update_req` はネイティブ Agent が処理し、APK 制御ブリッジ（`action: ota_update`）を呼びます。
- パッケージの置き換え後もアプリ専用ストレージ（デバイス ID / トークン）は保持されます。有効な場合は `MY_PACKAGE_REPLACED` が引き続き接続を再開します。

Rust Agent/CLI/Exchange、ブラウザー拡張機能、Android アプリ、Web コンソールのリリースバージョンを 0.1.27 に統一しました。今後は同時に更新します。Android versionCode は 30 です。パッケージ作成前に `python scripts/check-release-versions.py` を実行してください。

## Android Console の更新

ネイティブ Console には独自の **設定 → 更新を確認** ボタンがあり、ログイン前後のどちらでも使えます。アカウントの認証情報を使わず公開 Web サイトのマニフェストを読み、インストール済みビルドと公開済みの `versionCode` を比較します。マニフェストにビルドメタデータがなく、表示用バージョンが一致する場合は、最新であるとは断定せずダウンロードを案内します。

**インストールパッケージをダウンロード** は Web サイトの APK をブラウザーで開きます。Android の確認画面からインストールを完了してください。これは現在のスマートフォン上の Console を更新します。デバイス詳細ページの更新操作は引き続きリモートデバイスを対象とします。

## コンソールの「更新を確認」（統合フロー）

デバイス詳細には「更新を確認」操作だけを残します。まず `update_device { check_only: true }` を送信します。

- `up_to_date` → 「最新バージョン x.y.z です」を表示します。
- `available` → 「現在 → 最新（サイズ）」を表示し、ユーザーが「更新を配信 / 後で」を選択します。確認後に `check_only: false` を送り、進行状況と結果を表示します。
- Android への配信後に「インストール待ち…」が返った場合、デバイス上でシステムのインストールを確認するよう案内します。
- デバイスがオフライン、またはブラウザーデバイスの場合は理由を直接表示します。非対応プラットフォームでは「このデバイスはリモート更新に対応していません」を表示します。

結果メッセージには `current <版本>` と `size <字节> bytes` を含めます。

任意の稼働監視 watchdog（`--watchdog`、`REMOTE_WATCHDOG=1`）については、リポジトリの `docs/watchdog.md` も参照してください。

Android の診断画面には READ_LOGS 権限なしでも最新の自動更新結果と時刻が表示されます。固定メッセージで HTTP 状態、DNS、タイムアウト、TLS、マニフェスト、APK サイズ・ハッシュ、インストール権限の失敗を区別します。同じ安全なメッセージを RemoteAgentOTA タグで logcat に記録します。端末全体のログには引き続き READ_LOGS が必要です。例外の URL、パス、認証情報は記録しません。
