diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index e55bd11..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,98 +0,0 @@ -# OpenCode ECC + OpenChamber + Tailscale DevContainer -# 🚀 最適化版: ビルド時間50%短縮 & キャッシュ効率最大化 - -# ===== ステージ1: システム基盤構築 ===== -FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 AS system-base - -# 基本情報 & 環境変数(変更頻度低 -> 上位レイヤー) -LABEL maintainer="OpenCode ECC DevContainer" -LABEL description="Optimized OpenCode + ECC + OpenChamber + Tailscale development environment" -LABEL version="1.1.0-optimized" - -ENV NODE_VERSION=22 \ - DEBIAN_FRONTEND=noninteractive \ - TZ=Asia/Tokyo \ - VOLTA_HOME="/opt/volta" \ - PATH="/opt/volta/bin:$PATH" - -# ===== システムパッケージ(最優先キャッシュ) ===== -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - apt-get update && apt-get install -y --no-install-recommends \ - curl wget git vim nano htop jq unzip zip \ - build-essential ca-certificates gnupg lsb-release \ - software-properties-common apt-transport-https sudo \ - && apt-get autoremove -y && apt-get autoclean - -# ===== 並列インストール: Volta + Tailscale + uv ===== -RUN --mount=type=cache,target=/tmp/install-cache \ - # Volta インストール (システム全体) - curl -sSL https://get.volta.sh | bash -s -- --skip-setup && \ - # Tailscale インストール (並列) - curl -fsSL https://tailscale.com/install.sh | sh & \ - # uv インストール (並列) - curl -LsSf https://astral.sh/uv/install.sh | CARGO_HOME=/opt/cargo sh & \ - # 並列処理完了待ち - wait - -# Volta Node.js セットアップ -RUN /opt/volta/bin/volta install node@${NODE_VERSION} npm - -# ===== ステージ2: 開発ツール構築 ===== -FROM system-base AS dev-tools - -# npm グローバルキャッシュ最適化 -ENV npm_config_cache=/tmp/npm-cache -RUN --mount=type=cache,target=/tmp/npm-cache \ - # 並列npm install(依存関係なし) - npm install -g --prefer-offline opencode-ai & \ - npm install -g --prefer-offline @openchamber/web & \ - npm install -g --prefer-offline ecc-universal & \ - # 並列処理完了待ち - wait && \ - # ECC ajv依存関係修正(既知の問題対応) - ECC_DIR=$(npm list -g ecc-universal 2>/dev/null | head -n1 | awk '{print $1}')/node_modules/ecc-universal && \ - if [[ -d "$ECC_DIR" ]]; then \ - cd "$ECC_DIR" && npm install ajv 2>/dev/null || true; \ - fi && \ - # グローバル ajv もインストール(フォールバック) - npm install -g ajv 2>/dev/null || true - -# ===== ステージ3: ユーザー環境(統合版) ===== -FROM dev-tools AS final - -# VSCode ユーザー作成(条件付き - DevContainer対応) -RUN if ! id "vscode" &>/dev/null; then \ - useradd -m -s /bin/bash vscode; \ - fi && \ - usermod -aG sudo vscode 2>/dev/null || true && \ - echo "vscode ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \ - # 必要ディレクトリ作成(権限エラー対策強化) - mkdir -p /home/vscode/{.opencode,.config,workspace} && \ - mkdir -p /home/vscode/.opencode/{.agents,.agents/skills} && \ - # 環境変数設定を .bashrc に追加 - echo 'export VOLTA_HOME="/opt/volta"' >> /home/vscode/.bashrc && \ - echo 'export PATH="/opt/volta/bin:/opt/cargo/bin:$PATH"' >> /home/vscode/.bashrc && \ - # 権限設定(一括・強化版) - chown -R vscode:vscode /home/vscode && \ - chmod -R 755 /home/vscode/.opencode - -# ===== 最終設定(変更頻度高 -> 下位レイヤー) ===== -WORKDIR /workspace - -# ポート公開 -EXPOSE 3000 4095 8080 - -# ヘルスチェック(軽量化) -HEALTHCHECK --interval=45s --timeout=5s --start-period=30s --retries=3 \ - CMD pgrep -f "opencode\|openchamber" > /dev/null || exit 1 - -# エントリーポイント(最後にコピー = 変更時のレイヤー影響最小化) -COPY --chown=vscode:vscode .devcontainer/entrypoint.sh /usr/local/bin/ -RUN chmod +x /usr/local/bin/entrypoint.sh - -USER vscode -ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD ["sleep", "infinity"] -# /etc/hosts にホスト名を追加 -RUN echo "127.0.0.1 $(hostname)" >> /etc/hosts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 594538a..8046eb7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,6 @@ { "name": "OpenCode ECC + OpenChamber + Tailscale", - "dockerComposeFile": "docker-compose.yml", - "service": "opencode-dev", - "workspaceFolder": "/workspace", - "shutdownAction": "stopCompose", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installZsh": true, @@ -26,6 +23,12 @@ "ghcr.io/devcontainers/features/git:1": { "ppa": true, "version": "latest" + }, + "ghcr.io/devcontainers/features/python:1": { + "version": "3.11" + }, + "ghcr.io/devcontainers/features/github-cli:1": { + "installDirectlyFromGitHubRelease": true } }, "customizations": { @@ -44,7 +47,11 @@ ], "settings": { "terminal.integrated.defaultProfile.linux": "zsh", - "python.defaultInterpreterPath": "/usr/local/python/current/bin/python" + "python.defaultInterpreterPath": "/usr/local/python/current/bin/python", + "files.watcherExclude": { + "**/node_modules/**": true, + "**/.opencode/**": true + } } } }, @@ -67,11 +74,24 @@ "protocol": "http" } }, - "postCreateCommand": ".devcontainer/setup.sh", - "postStartCommand": ".devcontainer/startup.sh", - "postAttachCommand": { - "welcome": "echo '🚀 OpenCode ECC DevContainer へようこそ!' && echo '' && echo '📋 次のステップ:' && echo ' 1️⃣ .env.template を .env にコピー' && echo ' 2️⃣ 必要に応じて .env を編集' && echo ' 3️⃣ 初回プロジェクト設定: ./.devcontainer/interactive-setup.sh' && echo '' && echo '🎨 サービスURL:' && echo ' 📍 OpenChamber: http://localhost:3000' && echo ' 🤖 OpenCode CLI: http://localhost:4095' && echo ' 📊 ダッシュボード: http://localhost:8080'" + "postCreateCommand": ".devcontainer/setup-simple.sh", + "postAttachCommand": ".devcontainer/startup-simple.sh", + "containerEnv": { + "OPENCODE_AUTO_START": "true", + "OPENCODE_VERSION": "1.3.9", + "OPENCODE_STARTUP_TIMEOUT_SECONDS": "60", + "OPENCODE_HOST": "0.0.0.0", + "OPENCODE_PORT": "4095", + "OPENCHAMBER_HOST": "0.0.0.0", + "OPENCHAMBER_PORT": "3000", + "ECC_PROFILE": "developer", + "TAILSCALE_HOSTNAME": "opencode-dev", + "NODE_ENV": "development" }, + "runArgs": [ + "--cap-add=NET_ADMIN", + "--device=/dev/net/tun" + ], "remoteUser": "vscode", "mounts": [ "source=opencode-data,target=/home/vscode/.opencode,type=volume", diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml deleted file mode 100644 index ce4681d..0000000 --- a/.devcontainer/docker-compose.yml +++ /dev/null @@ -1,70 +0,0 @@ -version: "3.8" - -services: - opencode-dev: - build: - context: .. - dockerfile: .devcontainer/Dockerfile - # 🚀 ビルド最適化設定 - args: - - BUILDKIT_INLINE_CACHE=1 - cache_from: - - ghcr.io/opencode-ecc-devcontainer/cache:buildcache - target: final - # 並列ビルド有効化 - platforms: - - linux/amd64 - container_name: opencode-ecc-dev - hostname: opencode-dev - - # 特権モード(Tailscale用) - privileged: true - - # ネットワーク設定 - network_mode: host - - # 環境変数 - environment: - - NODE_ENV=development - - TAILSCALE_HOSTNAME=opencode-dev - - TAILSCALE_AUTH_KEY=${TAILSCALE_AUTH_KEY:-} - - OPENCODE_HOST=0.0.0.0 - - OPENCODE_PORT=4095 - - OPENCHAMBER_HOST=0.0.0.0 - - OPENCHAMBER_PORT=3000 - - ECC_PROFILE=developer - - # ボリューム - volumes: - - ../:/workspace:cached - - opencode-data:/home/vscode/.opencode - - tailscale-state:/var/lib/tailscale - - tailscale-run:/run/tailscale - - /var/run/docker.sock:/var/run/docker-host.sock - - # ポート(host network使用時は不要だが明示) - ports: - - "3000:3000" # OpenChamber - - "4095:4095" # OpenCode CLI - - "8080:8080" # Development - - # 開発用設定 - stdin_open: true - tty: true - - # ヘルスチェック - healthcheck: - test: - ["CMD", "curl", "-f", "http://localhost:3000/health", "||", "exit", "1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 60s - -volumes: - opencode-data: - driver: local - tailscale-state: - driver: local - tailscale-run: - driver: local diff --git a/.devcontainer/setup-simple.sh b/.devcontainer/setup-simple.sh new file mode 100755 index 0000000..9a6656d --- /dev/null +++ b/.devcontainer/setup-simple.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# OpenCode ECC DevContainer セットアップスクリプト +# DevContainer 作成時に一度だけ実行される(ai-harness-template ベース) + +set -e + +echo "🚀 OpenCode ECC + OpenChamber 環境をセットアップ中..." +echo "==============================================" + +# 基本パッケージの確認・インストール +echo "📦 基本パッケージ確認中..." +sudo apt-get update -y +sudo apt-get install -y curl wget unzip build-essential + +# Tailscale をインストール +if ! command -v tailscale >/dev/null 2>&1; then + echo "📦 Tailscale をインストール中..." + curl -fsSL https://tailscale.com/install.sh | sh +fi + +# uv (Python パッケージマネージャー) をインストール +if ! command -v uv >/dev/null 2>&1; then + echo "📦 uv (Python パッケージマネージャー) をインストール中..." + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.cargo/bin:$PATH" +fi + +# Node.js とnpmのバージョン確認 +echo "📦 Node.js: $(node --version)" +echo "📦 npm: $(npm --version)" +echo "📦 Python: $(python --version)" + +# OpenCode AI をグローバルインストール +echo "⬇️ OpenCode AI をインストール中..." +OPENCODE_VERSION="${OPENCODE_VERSION:-1.3.9}" +if npm install -g "opencode-ai@${OPENCODE_VERSION}"; then + echo "✅ OpenCode AI インストール完了" +else + echo "⚠️ OpenCode AI インストール失敗(継続します)" +fi + +# OpenChamber をグローバルインストール +echo "⬇️ OpenChamber をインストール中..." +if npm install -g @openchamber/web; then + echo "✅ OpenChamber インストール完了" +else + echo "⚠️ OpenChamber インストール失敗(継続します)" +fi + +# ECC (everything-claude-code) をインストール +echo "⬇️ ECC をインストール中..." +if npm install -g ecc-universal; then + echo "✅ ECC インストール完了" + + # ECC の依存関係修正(ajv問題対策) + echo "🔧 ECC 依存関係修正中..." + ECC_DIR=$(npm list -g ecc-universal 2>/dev/null | head -n1 | awk '{print $1}')/node_modules/ecc-universal + if [ -d "$ECC_DIR" ]; then + cd "$ECC_DIR" + npm install ajv 2>/dev/null || true + npm install 2>/dev/null || true + cd - >/dev/null + echo "✅ ECC 依存関係修正完了" + fi +else + echo "⚠️ ECC インストール失敗(継続します)" +fi + +# .opencode ディレクトリの権限設定(権限問題対策) +echo "🔧 .opencode ディレクトリ権限設定中..." +mkdir -p /home/vscode/.opencode +sudo chown -R vscode:vscode /home/vscode/.opencode +chmod -R 755 /home/vscode/.opencode +chmod -R u+w /home/vscode/.opencode +echo "✅ .opencode 権限設定完了" + +# プロジェクト用のディレクトリ作成 +mkdir -p .opencode-logs +mkdir -p .temp + +# 権限設定 +chmod +x scripts/* 2>/dev/null || true + +# .env ファイル作成 +if [ ! -f ".env" ] && [ -f ".env.template" ]; then + cp .env.template .env + echo "✅ .env ファイルを作成しました" +fi + +echo "" +echo "✅ 全セットアップ完了!" +echo "" +echo "🎯 利用可能なサービス:" +echo " - OpenChamber Web UI: ポート 3000" +echo " - OpenCode CLI Server: ポート 4095" +echo " - Development Server: ポート 8080" +echo "" +echo "📝 すぐに始められます:" +echo " 1. VS Code の 'PORTS' タブから各サービスにアクセス" +echo " 2. OpenChamber でAIコーディングを開始!" +echo " 3. Tailscale設定が必要な場合は .env を編集" +echo "" \ No newline at end of file diff --git a/.devcontainer/startup-simple.sh b/.devcontainer/startup-simple.sh new file mode 100755 index 0000000..4c56cdd --- /dev/null +++ b/.devcontainer/startup-simple.sh @@ -0,0 +1,167 @@ +#!/bin/bash + +# OpenCode ECC サービス起動スクリプト +# DevContainer 接続時に毎回実行される(ai-harness-template ベース) + +set -e + +LOCK_FILE="/tmp/opencode-ecc-start-services.lock" +exec 9>"$LOCK_FILE" +if ! flock -w 120 9; then + echo "❌ start-services.sh の排他ロック取得に失敗しました" + echo " 既存の起動処理が長時間実行中の可能性があります" + exit 1 +fi + +# ワークスペースディレクトリの確認 +WORKSPACE_DIR="${containerWorkspaceFolder:-$(pwd)}" +cd "$WORKSPACE_DIR" + +# .env がなければテンプレートから作成 +if [ ! -f ".env" ] && [ -f ".env.template" ]; then + cp .env.template .env +fi + +# .env があれば読み込んで環境変数として展開 +if [ -f ".env" ]; then + set -a + # shellcheck disable=SC1091 + . ./.env + set +a +fi + +# 実行時に必要なディレクトリを保証 +mkdir -p .opencode-logs +mkdir -p .temp + +# デフォルトURL +OPENCODE_CLI_URL="http://localhost:4095" +OPENCHAMBER_URL="http://localhost:3000" +DASHBOARD_URL="http://localhost:8080" + +# 環境変数設定 +OPENCODE_VERSION="${OPENCODE_VERSION:-1.3.9}" +OPENCODE_STARTUP_TIMEOUT_SECONDS="${OPENCODE_STARTUP_TIMEOUT_SECONDS:-60}" +OPENCODE_START_RETRIES="${OPENCODE_START_RETRIES:-3}" +TAILSCALE_HOSTNAME="${TAILSCALE_HOSTNAME:-opencode-dev}" + +get_pid_by_port() { + local port="$1" + ss -ltnp 2>/dev/null | grep -E ":${port}[[:space:]]" | sed -n 's/.*pid=\([0-9]\+\).*/\1/p' | head -n 1 +} + +wait_for_port() { + local port="$1" + local retries="${2:-10}" + local delay="${3:-1}" + local i + for i in $(seq 1 "$retries"); do + if ss -ltn 2>/dev/null | grep -qE ":${port}[[:space:]]"; then + return 0 + fi + sleep "$delay" + done + return 1 +} + +is_pid_alive() { + local pid="$1" + [ -n "$pid" ] && ps -p "$pid" >/dev/null 2>&1 +} + +start_opencode_cli() { + local host_arg="--host 0.0.0.0" + if command -v opencode >/dev/null 2>&1; then + nohup setsid opencode start --port 4095 $host_arg > .opencode-logs/opencode-cli.log 2>&1 & + else + nohup setsid npx --yes "opencode-ai@${OPENCODE_VERSION}" start --port 4095 $host_arg > .opencode-logs/opencode-cli.log 2>&1 & + fi +} + +start_openchamber() { + if command -v openchamber >/dev/null 2>&1; then + nohup setsid openchamber --port 3000 --host 0.0.0.0 > .opencode-logs/openchamber.log 2>&1 & + else + nohup setsid npx --yes @openchamber/web --port 3000 --host 0.0.0.0 > .opencode-logs/openchamber.log 2>&1 & + fi +} + +echo "🚀 OpenCode ECC サービスを起動中..." + +# Tailscale の起動(AuthKey があれば自動で参加) +if command -v tailscaled >/dev/null 2>&1; then + mkdir -p /var/lib/tailscale + + if ! pgrep -x tailscaled >/dev/null 2>&1; then + if sudo -n true 2>/dev/null; then + nohup setsid sudo -n tailscaled --state=/var/lib/tailscale/tailscaled.state --tun=userspace-networking > .opencode-logs/tailscaled.log 2>&1 & + sleep 2 + else + echo "⚠️ sudo が使えないため tailscaled の起動をスキップします" + fi + fi + + if [ -n "${TAILSCALE_AUTH_KEY:-}" ] && [ "${TAILSCALE_AUTH_KEY}" != "your-auth-key-here" ]; then + if ! sudo -n tailscale up --authkey "$TAILSCALE_AUTH_KEY" --hostname "$TAILSCALE_HOSTNAME" --accept-dns=false 2>/dev/null; then + echo "⚠️ Tailscale のセットアップに失敗しました" + else + echo "✅ Tailscale 接続完了" + fi + else + echo "⚠️ TAILSCALE_AUTH_KEY が未設定のため Tailscale 参加をスキップします" + fi +fi + +# OpenCode CLI の起動 +echo "⬇️ OpenCode CLI を起動中..." +EXISTING_CLI_PID="$(get_pid_by_port 4095)" +if [ -n "$EXISTING_CLI_PID" ] && is_pid_alive "$EXISTING_CLI_PID"; then + echo "✅ OpenCode CLI は既に起動済みです (PID: $EXISTING_CLI_PID)" +else + start_opencode_cli + if wait_for_port 4095 "$OPENCODE_STARTUP_TIMEOUT_SECONDS" 1; then + ACTIVE_CLI_PID="$(get_pid_by_port 4095)" + echo "✅ OpenCode CLI 起動完了 (PID: $ACTIVE_CLI_PID)" + else + echo "❌ OpenCode CLI の起動に失敗しました" + echo " ログ: .opencode-logs/opencode-cli.log" + fi +fi + +# OpenChamber の起動 +echo "⬇️ OpenChamber を起動中..." +EXISTING_CHAMBER_PID="$(get_pid_by_port 3000)" +if [ -n "$EXISTING_CHAMBER_PID" ] && is_pid_alive "$EXISTING_CHAMBER_PID"; then + echo "✅ OpenChamber は既に起動済みです (PID: $EXISTING_CHAMBER_PID)" +else + start_openchamber + if wait_for_port 3000 15 1; then + ACTIVE_CHAMBER_PID="$(get_pid_by_port 3000)" + echo "✅ OpenChamber 起動完了 (PID: $ACTIVE_CHAMBER_PID)" + else + echo "❌ OpenChamber の起動に失敗しました" + echo " ログ: .opencode-logs/openchamber.log" + fi +fi + +# バックグラウンドプロセスがロックを継承しないようにする +exec 9>&- + +# 起動完了メッセージ +echo "" +echo "==============================================" +echo "🤖 OpenCode ECC 環境 起動完了!" +echo "" +echo "📱 利用可能なサービス:" +echo " 🎨 OpenChamber Web UI: $OPENCHAMBER_URL" +echo " 🤖 OpenCode CLI Server: $OPENCODE_CLI_URL" +echo " 📊 Development Server: $DASHBOARD_URL" +echo "" +echo "🎯 クイックスタート:" +echo " 1. VS Code 'PORTS' タブから各サービスにアクセス" +echo " 2. OpenChamber: AIプロバイダー設定後、コーディング開始" +echo " 3. OpenCode CLI: APIサーバーとして利用可能" +echo "" +echo "📚 ドキュメント: README.md | QUICK_START.md" +echo "==============================================" +echo "" \ No newline at end of file