Created
March 10, 2026 01:41
-
-
Save koki-h/bfbce63f7a3ec20b70978d0f9b4056d5 to your computer and use it in GitHub Desktop.
opencodeサーバ起動とChromeでVISを開くのをまとめて行うスクリプト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # macOS 用。opencode serve を起動し、Chrome の Local Network Access ポリシーを設定したうえで | |
| # https://xenodrive.github.io/vis/ を app 風ウィンドウで開きます。 | |
| # ウィンドウを閉じたらローカルサーバも自動停止します。 | |
| set -euo pipefail | |
| # ========================= | |
| # 設定 | |
| # ========================= | |
| OPENCODE_PORT="${OPENCODE_PORT:-4096}" | |
| OPENCODE_HOST="${OPENCODE_HOST:-127.0.0.1}" | |
| OPENCODE_ORIGIN="${OPENCODE_ORIGIN:-https://xenodrive.github.io}" | |
| VIS_URL="${VIS_URL:-https://xenodrive.github.io/vis/}" | |
| CHROME_APP_NAME="${CHROME_APP_NAME:-Google Chrome}" | |
| RUNTIME_DIR="$HOME/.opencode-vis-launcher" | |
| PID_FILE="$RUNTIME_DIR/opencode.pid" | |
| LOG_FILE="$RUNTIME_DIR/opencode.log" | |
| USER_DATA_DIR="$HOME/Library/Application Support/OpenCodeVisApp" | |
| # Chrome policy | |
| CHROME_POLICY_DOMAIN="${CHROME_POLICY_DOMAIN:-com.google.Chrome}" | |
| CHROME_POLICY_PLIST="${CHROME_POLICY_PLIST:-/Library/Managed Preferences/${CHROME_POLICY_DOMAIN}.plist}" | |
| CHROME_POLICY_ALLOWED_URL="${CHROME_POLICY_ALLOWED_URL:-https://xenodrive.github.io}" | |
| WRITE_CHROME_POLICY="${WRITE_CHROME_POLICY:-1}" | |
| mkdir -p "$RUNTIME_DIR" | |
| mkdir -p "$USER_DATA_DIR" | |
| # Automator / Finder 起動では PATH が極端に短いことが多いので補強する | |
| export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/.local/bin:$HOME/bin:$HOME/.npm-global/bin:$HOME/node_modules/.bin:$HOME/.bun/bin:$PATH" | |
| is_server_alive() { | |
| curl -fsS "http://${OPENCODE_HOST}:${OPENCODE_PORT}/app" >/dev/null 2>&1 || \ | |
| curl -fsS "http://${OPENCODE_HOST}:${OPENCODE_PORT}/" >/dev/null 2>&1 | |
| } | |
| cleanup_stale_pid() { | |
| if [[ -f "$PID_FILE" ]]; then | |
| local old_pid | |
| old_pid="$(cat "$PID_FILE" 2>/dev/null || true)" | |
| if [[ -n "$old_pid" ]] && ! kill -0 "$old_pid" 2>/dev/null; then | |
| rm -f "$PID_FILE" | |
| fi | |
| fi | |
| } | |
| find_opencode() { | |
| # 1) 今の PATH | |
| if command -v opencode >/dev/null 2>&1; then | |
| command -v opencode | |
| return 0 | |
| fi | |
| # 2) zsh のログインシェル環境を読む(mac の通常利用に近い) | |
| local from_zsh="" | |
| from_zsh="$(zsh -lic 'command -v opencode 2>/dev/null || true' 2>/dev/null | tail -n 1)" | |
| if [[ -n "$from_zsh" && -x "$from_zsh" ]]; then | |
| echo "$from_zsh" | |
| return 0 | |
| fi | |
| # 3) よくある配置場所を総当たり | |
| local candidates=( | |
| "/opt/homebrew/bin/opencode" | |
| "/usr/local/bin/opencode" | |
| "$HOME/.local/bin/opencode" | |
| "$HOME/bin/opencode" | |
| "$HOME/.npm-global/bin/opencode" | |
| "$HOME/.bun/bin/opencode" | |
| ) | |
| local p | |
| for p in "${candidates[@]}"; do | |
| if [[ -x "$p" ]]; then | |
| echo "$p" | |
| return 0 | |
| fi | |
| done | |
| return 1 | |
| } | |
| ensure_chrome_policy() { | |
| [[ "$WRITE_CHROME_POLICY" == "1" ]] || return 0 | |
| echo "Chrome ポリシーを確認します: $CHROME_POLICY_PLIST" | |
| echo "許可 URL: $CHROME_POLICY_ALLOWED_URL" | |
| # 既に許可済みなら何もしない | |
| if sudo defaults read "$CHROME_POLICY_PLIST" LocalNetworkAccessAllowedForUrls 2>/dev/null | grep -Fq "$CHROME_POLICY_ALLOWED_URL"; then | |
| echo "Chrome ポリシーは既に設定済みです。" | |
| return 0 | |
| fi | |
| echo "Chrome ポリシーを書き込みます(管理者権限が必要です)..." | |
| sudo mkdir -p "/Library/Managed Preferences" | |
| # 配列を作り直して、必要 URL を入れる | |
| sudo /usr/libexec/PlistBuddy -c "Delete :LocalNetworkAccessAllowedForUrls" "$CHROME_POLICY_PLIST" 2>/dev/null || true | |
| sudo /usr/libexec/PlistBuddy -c "Add :LocalNetworkAccessAllowedForUrls array" "$CHROME_POLICY_PLIST" | |
| sudo /usr/libexec/PlistBuddy -c "Add :LocalNetworkAccessAllowedForUrls:0 string $CHROME_POLICY_ALLOWED_URL" "$CHROME_POLICY_PLIST" | |
| echo "Chrome ポリシーを書き込みました。" | |
| echo "既に Chrome が起動中なら、完全終了後に再起動したほうが確実です。" | |
| } | |
| stop_server() { | |
| if [[ -f "$PID_FILE" ]]; then | |
| local pid | |
| pid="$(cat "$PID_FILE" 2>/dev/null || true)" | |
| if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then | |
| echo "opencode server を停止します (PID: $pid)" | |
| kill "$pid" 2>/dev/null || true | |
| for _ in {1..10}; do | |
| if ! kill -0 "$pid" 2>/dev/null; then | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| if kill -0 "$pid" 2>/dev/null; then | |
| kill -9 "$pid" 2>/dev/null || true | |
| fi | |
| fi | |
| rm -f "$PID_FILE" | |
| fi | |
| } | |
| start_server() { | |
| cleanup_stale_pid | |
| if is_server_alive; then | |
| echo "opencode server は既に起動しています: http://${OPENCODE_HOST}:${OPENCODE_PORT}" | |
| return 0 | |
| fi | |
| local opencode_bin="" | |
| if ! opencode_bin="$(find_opencode)"; then | |
| cat >&2 <<MSG | |
| エラー: opencode コマンドが見つかりません。 | |
| 対処候補: | |
| 1. ターミナルで 'which opencode' を実行して場所を確認する | |
| 2. このスクリプト先頭で OPENCODE_BIN にその絶対パスを指定する | |
| 例: OPENCODE_BIN=/opt/homebrew/bin/opencode | |
| 現在の PATH: | |
| $PATH | |
| MSG | |
| exit 1 | |
| fi | |
| echo "使用する opencode: $opencode_bin" | |
| echo "opencode serve を起動します..." | |
| nohup "$opencode_bin" serve --cors "$OPENCODE_ORIGIN" --hostname "$OPENCODE_HOST" --port "$OPENCODE_PORT" \ | |
| >"$LOG_FILE" 2>&1 & | |
| local pid=$! | |
| echo "$pid" > "$PID_FILE" | |
| for _ in {1..60}; do | |
| if is_server_alive; then | |
| echo "opencode server 起動完了: http://${OPENCODE_HOST}:${OPENCODE_PORT}" | |
| return 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "エラー: opencode server の起動確認に失敗しました。ログ: $LOG_FILE" >&2 | |
| exit 1 | |
| } | |
| open_vis_app() { | |
| local chrome_path="/Applications/${CHROME_APP_NAME}.app" | |
| if [[ ! -d "$chrome_path" ]]; then | |
| echo "エラー: /Applications/${CHROME_APP_NAME}.app が見つかりません。" >&2 | |
| echo "CHROME_APP_NAME を 'Google Chrome' / 'Google Chrome Canary' / 'Microsoft Edge' などに変更してください。" >&2 | |
| exit 1 | |
| fi | |
| echo "Visualizer を単体アプリ風ウィンドウで開きます..." | |
| open -na "$CHROME_APP_NAME" --args \ | |
| --app="$VIS_URL" \ | |
| --user-data-dir="$USER_DATA_DIR" \ | |
| --disable-background-mode \ | |
| --window-size=1440,980 | |
| } | |
| wait_for_vis_close() { | |
| local found_once=0 | |
| echo "VIS ウィンドウが閉じられるのを監視します..." | |
| while true; do | |
| if pgrep -af "$USER_DATA_DIR" >/dev/null 2>&1; then | |
| found_once=1 | |
| else | |
| if [[ "$found_once" -eq 1 ]]; then | |
| echo "VIS 用 Chrome が終了しました。" | |
| return 0 | |
| fi | |
| fi | |
| sleep 2 | |
| done | |
| } | |
| trap 'stop_server' EXIT INT TERM | |
| ensure_chrome_policy | |
| start_server | |
| open_vis_app | |
| wait_for_vis_close | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment