Monorepo for Aesthetic.Computer aesthetic.computer
at main 982 lines 40 kB view raw
1#!/usr/bin/env fish 2 3# Log file for aesthetic function to tail during wait 4set -g ENTRY_LOG /tmp/entry-fish.log 5set -g ENTRY_LOG_DIR /home/me/.entry-logs 6if test -d /workspaces/aesthetic-computer/.devcontainer 7 set -g ENTRY_LOG_DIR /workspaces/aesthetic-computer/.devcontainer/entry-logs 8end 9set -l entry_ts (date +%Y%m%d_%H%M%S) 10set -g ENTRY_LOG_REAL $ENTRY_LOG_DIR/entry-$entry_ts.log 11 12mkdir -p $ENTRY_LOG_DIR 13echo "" > $ENTRY_LOG_REAL 14ln -sf $ENTRY_LOG_REAL $ENTRY_LOG 15ln -sf $ENTRY_LOG_REAL $ENTRY_LOG_DIR/latest.log 16echo "" > $ENTRY_LOG 17 18# Aggressive logging function - writes immediately with timestamp and syncs to disk 19function log 20 set -l timestamp (date '+%H:%M:%S.%3N') 21 set -l msg "[$timestamp] $argv" 22 builtin echo $msg 23 builtin echo $msg >> $ENTRY_LOG_REAL 2>/dev/null 24 # Force sync to disk immediately so we don't lose logs on crash 25 sync 2>/dev/null 26end 27 28# Log with specific level prefix 29function log_info 30 log "ℹ️ $argv" 31end 32 33function log_ok 34 log "$argv" 35end 36 37function log_warn 38 log "⚠️ $argv" 39end 40 41function log_error 42 log "$argv" 43end 44 45function log_step 46 log "🔹 $argv" 47end 48 49# Simple wrapper: append each echo to log file too (keep for backward compat) 50# We override echo within this script 51function echo 52 builtin echo $argv 53 builtin echo "[" (date '+%H:%M:%S') "] $argv" >> $ENTRY_LOG_REAL 2>/dev/null 54end 55 56# Run a command and capture output to the entry log. 57function log_cmd 58 set -l cmd_str (string join ' ' -- $argv) 59 log_step "Running: $cmd_str" 60 command $argv >> $ENTRY_LOG_REAL 2>&1 61 set -l cmd_status $status 62 if test $cmd_status -ne 0 63 log_error "Command failed ($cmd_status): $cmd_str" 64 else 65 log_ok "Command succeeded: $cmd_str" 66 end 67 sync 2>/dev/null 68 return $cmd_status 69end 70 71# Run a command with a timeout if available. 72function log_cmd_timeout 73 set -l seconds $argv[1] 74 set -l cmd $argv[2..-1] 75 log_step "Running with "$seconds"s timeout: "(string join ' ' -- $cmd) 76 if type -q timeout 77 log_cmd timeout $seconds $cmd 78 else 79 log_cmd $cmd 80 end 81 return $status 82end 83 84# Start CDP tunnel without blocking startup if SSH auth is missing. 85function start_cdp_tunnel 86 set -l ssh_args -f -N -o StrictHostKeyChecking=no -o BatchMode=yes -o ExitOnForwardFailure=yes -o ConnectTimeout=5 -o ConnectionAttempts=1 -L 9333:127.0.0.1:9333 me@host.docker.internal 87 log_cmd_timeout 8 ssh $ssh_args 88 return $status 89end 90 91log "════════════════════════════════════════════════════════════════" 92log "🚀 ENTRY.FISH STARTING" 93log "════════════════════════════════════════════════════════════════" 94log_info "Timestamp: "(date -Iseconds) 95log_info "Log file: $ENTRY_LOG_REAL" 96log_info "Log dir: $ENTRY_LOG_DIR" 97log_info "Hostname: "(cat /etc/hostname 2>/dev/null; or echo "unknown") 98log_info "User: "(whoami) 99log_info "PWD: "(pwd) 100 101# 🔍 Start Devcontainer Status Server EARLY (so VS Code can see boot progress) 102# This allows the Welcome Panel to show the boot process in real-time 103log_step "EARLY START: Devcontainer Status Server" 104if test -f /workspaces/aesthetic-computer/artery/devcontainer-status.mjs 105 # Kill any existing instance first 106 pkill -f "devcontainer-status" 2>/dev/null 107 sleep 0.1 108 nohup node /workspaces/aesthetic-computer/artery/devcontainer-status.mjs --server >/tmp/devcontainer-status.log 2>&1 & 109 disown 110 log_ok "Status Server started early on http://127.0.0.1:7890" 111else 112 log_warn "devcontainer-status.mjs not found, will try later" 113end 114 115log_step "PHASE 1: Environment sync" 116 117# --- Sync secrets from vault to devcontainer env --- 118# The vault stores the canonical secrets; copy them to devcontainer on startup 119set -l vault_env ~/aesthetic-computer-vault/.devcontainer/envs/devcontainer.env 120set -l devcontainer_env ~/aesthetic-computer/.devcontainer/envs/devcontainer.env 121if test -f $vault_env 122 if test -f $devcontainer_env 123 # Merge: update devcontainer.env with any keys from vault (vault wins) 124 for line in (cat $vault_env) 125 set -l key (string split -m1 '=' -- $line)[1] 126 if test -n "$key" 127 # Remove old key if exists, then append new 128 sed -i "/^$key=/d" $devcontainer_env 2>/dev/null 129 echo $line >> $devcontainer_env 130 end 131 end 132 log_ok "Synced secrets from vault to devcontainer.env" 133 else 134 # No devcontainer.env, just copy from vault 135 cp $vault_env $devcontainer_env 136 log_ok "Copied secrets from vault to devcontainer.env" 137 end 138else 139 log_warn "Vault env not found at $vault_env" 140end 141 142# --- Setup session-server SSH key from vault --- 143set -l ss_key_src ~/aesthetic-computer-vault/session-server/session_server 144set -l ss_key_dst ~/.ssh/session_server 145if test -f $ss_key_src; and not test -f $ss_key_dst 146 # Ensure .ssh directory exists with correct ownership and permissions 147 sudo mkdir -p ~/.ssh 148 sudo chown me:me ~/.ssh 149 sudo chmod 700 ~/.ssh 150 151 cp $ss_key_src $ss_key_dst 152 cp "$ss_key_src.pub" "$ss_key_dst.pub" 153 chmod 600 $ss_key_dst 154 chmod 644 "$ss_key_dst.pub" 155 156 # Create config file if it doesn't exist with correct ownership 157 if not test -f ~/.ssh/config 158 touch ~/.ssh/config 159 chmod 600 ~/.ssh/config 160 end 161 162 # Add SSH config entry if missing 163 if not grep -q "Host session-server" ~/.ssh/config 2>/dev/null 164 echo "" >> ~/.ssh/config 165 echo "Host session-server" >> ~/.ssh/config 166 echo " HostName 157.245.134.225" >> ~/.ssh/config 167 echo " User root" >> ~/.ssh/config 168 echo " IdentityFile ~/.ssh/session_server" >> ~/.ssh/config 169 echo " IdentitiesOnly yes" >> ~/.ssh/config 170 echo " StrictHostKeyChecking accept-new" >> ~/.ssh/config 171 end 172 log_ok "Session-server SSH key installed" 173else if not test -f $ss_key_src 174 log_warn "Session-server SSH key not found in vault" 175end 176 177log_step "PHASE 2: Checking for fast reload path" 178 179# Fast path for VS Code "Reload Window" - if .waiter exists and key processes running, skip setup 180if test -f /home/me/.waiter 181 log_info "Detected reload (found .waiter file)" 182 183 # Check if key processes are already running 184 set -l dockerd_running (pgrep -x dockerd 2>/dev/null) 185 set -l emacs_running (pgrep -f "emacs.*daemon" 2>/dev/null) 186 187 if test -n "$dockerd_running" 188 echo "✅ Docker daemon already running (PID: $dockerd_running)" 189 190 # Check if emacs daemon is running AND responsive 191 set -l emacs_config /home/me/aesthetic-computer/dotfiles/dot_config/emacs.el 192 if test -n "$emacs_running" 193 if emacsclient -e t >/dev/null 2>&1 194 echo "✅ Emacs daemon running and responsive (PID: $emacs_running)" 195 else 196 echo "⚠️ Emacs daemon zombie detected (PID: $emacs_running) - restarting..." 197 pkill -9 -f "emacs.*daemon" 2>/dev/null 198 pkill -9 emacs 2>/dev/null 199 sleep 1 200 emacs -q --daemon -l $emacs_config 2>&1 201 sleep 1 202 if emacsclient -e t >/dev/null 2>&1 203 echo "✅ Emacs daemon restarted successfully" 204 else 205 echo "❌ Failed to restart emacs daemon" 206 end 207 end 208 else 209 echo "⚠️ Emacs daemon not running - starting..." 210 emacs -q --daemon -l $emacs_config 2>&1 211 sleep 1 212 end 213 214 # Ensure CDP tunnel is up (for artery-tui to control VS Code on host) 215 set -l cdp_tunnel (pgrep -f "ssh.*9333.*host.docker.internal" 2>/dev/null) 216 if test -n "$cdp_tunnel" 217 echo "✅ CDP tunnel already running (PID: $cdp_tunnel)" 218 else 219 echo "🩸 Starting CDP tunnel..." 220 start_cdp_tunnel 221 if test $status -eq 0 222 echo "✅ CDP tunnel established (localhost:9333 → host:9333)" 223 else 224 echo "⚠️ CDP tunnel failed (artery may not control VS Code)" 225 end 226 end 227 228 echo "⚡ Skipping full setup - container already configured" 229 echo "✅ Ready! (fast reload path)" 230 exit 0 231 else 232 echo "⚠️ Docker daemon not found, running full setup..." 233 end 234end 235 236# Fix fish path if needed (Fedora installs to /usr/sbin instead of /usr/bin) 237if not test -f /usr/bin/fish; and test -f /usr/sbin/fish 238 sudo ln -sf /usr/sbin/fish /usr/bin/fish 239 echo "🐟 Created fish symlink: /usr/bin/fish -> /usr/sbin/fish" 240end 241 242# Function to ensure fish config directory has correct permissions 243function ensure_fish_config_permissions 244 set -l fish_config_dir /home/me/.config/fish 245 set -l fish_data_dir /home/me/.local/share/fish 246 247 echo "🔧 Fixing permissions for fish directories..." 248 249 # Fix the parent .config directory first (most important) 250 if test -d /home/me/.config 251 sudo chown -R me:me /home/me/.config 2>/dev/null 252 sudo chmod -R 755 /home/me/.config 2>/dev/null 253 echo "✅ Fixed permissions for /home/me/.config" 254 end 255 256 if test -d $fish_config_dir 257 # Fix ownership and permissions for fish config directory - be VERY aggressive 258 sudo chown -R me:me $fish_config_dir 2>/dev/null 259 sudo chmod -R 755 $fish_config_dir 2>/dev/null 260 sudo chmod 644 $fish_config_dir/*.fish 2>/dev/null 261 # Also fix individual subdirectories explicitly 262 sudo chown -R me:me $fish_config_dir/conf.d 2>/dev/null 263 sudo chown -R me:me $fish_config_dir/functions 2>/dev/null 264 sudo chown -R me:me $fish_config_dir/completions 2>/dev/null 265 echo "✅ Fixed permissions for $fish_config_dir" 266 end 267 268 if test -d $fish_data_dir 269 # Fix ownership and permissions for fish data directory 270 sudo chown -R me:me $fish_data_dir 2>/dev/null 271 sudo chmod -R 755 $fish_data_dir 2>/dev/null 272 echo "✅ Fixed permissions for $fish_data_dir" 273 end 274 275 # Fix /home/me/.local directory too 276 if test -d /home/me/.local 277 sudo chown -R me:me /home/me/.local 2>/dev/null 278 sudo chmod -R 755 /home/me/.local 2>/dev/null 279 echo "✅ Fixed permissions for /home/me/.local" 280 end 281 282 # Disable fish's universal variable file daemon (fishd) which causes permission issues 283 # We'll use fish_variables instead which is simpler and doesn't create temp files 284 set -U fish_greeting "" # Suppress greeting while we're at it 285 286 echo "✨ All permissions fixed!" 287end 288 289# Function to ensure correct Docker socket permissions 290function ensure_docker_socket_permissions 291 set -l DOCKER_SOCKET /var/run/docker.sock 292 if test -S $DOCKER_SOCKET 293 set -l DOCKER_GID (stat -c '%g' $DOCKER_SOCKET) 294 set -l CURRENT_DOCKER_GROUP_INFO (getent group $DOCKER_GID) 295 296 if test -z "$CURRENT_DOCKER_GROUP_INFO" # No group with this GID exists 297 if getent group docker > /dev/null 298 echo "Modifying existing docker group to GID $DOCKER_GID..." 299 sudo groupmod -g $DOCKER_GID docker 300 else 301 echo "Creating new docker group with GID $DOCKER_GID..." 302 sudo groupadd -g $DOCKER_GID docker 303 end 304 else # A group with this GID already exists, check if it's named 'docker' 305 set -l GROUP_NAME (echo $CURRENT_DOCKER_GROUP_INFO | cut -d: -f1) 306 if test "$GROUP_NAME" != "docker" 307 echo "Warning: Group with GID $DOCKER_GID exists but is named '$GROUP_NAME', not 'docker'. Manual intervention might be needed." 308 # Optionally, you could decide to add 'me' to this group anyway, 309 # or try to rename it if it's safe, or delete and recreate 'docker' group. 310 # For now, we'll proceed assuming 'docker' is the target group name. 311 if getent group docker > /dev/null 312 echo "Modifying existing docker group to GID $DOCKER_GID..." 313 sudo groupmod -g $DOCKER_GID docker 314 else 315 echo "Creating new docker group with GID $DOCKER_GID..." 316 sudo groupadd -g $DOCKER_GID docker 317 end 318 else 319 echo "Docker group '$GROUP_NAME' with GID $DOCKER_GID already exists." 320 end 321 end 322 323 # Ensure 'me' user is in the 'docker' group 324 if not groups me | string match -q -r '\\bdocker\\b' 325 echo "Adding user 'me' to docker group..." 326 sudo usermod -aG docker me 327 # Changes to group membership may require a new login session or `newgrp docker` 328 # to take effect immediately in the current shell. 329 # For a script, subsequent commands in this same script might not see the new group immediately. 330 # However, for processes spawned after this script, it should be fine. 331 else 332 echo "User 'me' is already in docker group." 333 end 334 else 335 echo "Docker socket $DOCKER_SOCKET not found." 336 end 337end 338 339function install_and_trust_certificate 340 set -l certificate_path $argv[1] 341 set -l certificate_key_path $argv[2] 342 set -l certificate_dir /etc/pki/ca-trust/source/anchors/ 343 344 if test -z "$certificate_path"; or test -z "$certificate_key_path" 345 return 346 end 347 348 if test -f $certificate_path 349 sudo cp $certificate_path $certificate_dir 350 end 351 352 if test -f $certificate_key_path 353 sudo cp $certificate_key_path $certificate_dir 354 end 355 356 sudo update-ca-trust 357end 358 359function ensure_ssl_dev_certs 360 set -l ssl_dir /home/me/aesthetic-computer/ssl-dev 361 set -l nanos_ssl_dir /home/me/aesthetic-computer/nanos/ssl 362 363 if not test -d $ssl_dir 364 return 365 end 366 367 if not type -q mkcert 368 echo "⚠️ mkcert not available; skipping automatic certificate generation." 369 return 370 end 371 372 set -l previous_dir (pwd) 373 cd $ssl_dir 374 375 set -l have_cert 1 376 if not test -f localhost.pem; or not test -f localhost-key.pem 377 set have_cert 0 378 end 379 380 if test $have_cert -eq 0 381 echo "🔐 Generating mkcert certificates for the dev container..." 382 if not test -d /home/me/.local/share/mkcert 383 echo "📥 Installing mkcert local CA..." 384 log_cmd_timeout 60 mkcert -install 385 if test $status -ne 0 386 echo "⚠️ mkcert CA installation failed. See entry.fish log for details." 387 end 388 if not type -q certutil 389 echo "📦 Installing nss-tools for certificate trust..." 390 log_cmd_timeout 300 sudo dnf install -y nss-tools 391 log_cmd_timeout 60 mkcert -install 392 end 393 end 394 395 log_cmd_timeout 120 env nogreet=true fish ./ssl-install.fish 396 if test $status -ne 0 397 echo "⚠️ Automatic certificate generation failed using ssl-install.fish." 398 cd $previous_dir 399 return 400 end 401 else 402 log_cmd_timeout 120 env nogreet=true fish ./ssl-install.fish --install-only 403 end 404 405 mkdir -p $nanos_ssl_dir 406 cp localhost.pem $nanos_ssl_dir/localhost.pem 407 cp localhost-key.pem $nanos_ssl_dir/localhost-key.pem 408 409 sudo chown me:me -R $ssl_dir 410 sudo chown me:me -R $nanos_ssl_dir 411 412 install_and_trust_certificate $ssl_dir/localhost.pem $ssl_dir/localhost-key.pem 413 414 cd $previous_dir 415end 416 417log_step "PHASE 3: Docker socket permissions" 418# Call the function to set up Docker socket permissions 419ensure_docker_socket_permissions 420 421log_step "PHASE 4: Starting daemons" 422# Start Docker daemon in the background if not already running 423if not pgrep -x dockerd >/dev/null 424 log_info "Starting Docker daemon..." 425 sudo dockerd >/tmp/dockerd.log 2>&1 & 426else 427 log_ok "Docker daemon already running." 428end 429 430# Start Ollama daemon in the background if available and not already running 431if type -q ollama 432 if not pgrep -x ollama >/dev/null 433 log_info "Starting Ollama daemon..." 434 ollama serve >/tmp/ollama.log 2>&1 & 435 else 436 log_ok "Ollama daemon already running." 437 end 438else 439 log_warn "Ollama not found; skipping." 440end 441 442log_step "PHASE 4b: Cockpit web interface" 443# Start Cockpit web server (no TLS for local dev, port 9090) 444# Terminal + system overview work without systemd; service/journal features need systemd 445set -l cockpit_ws_bin "" 446for p in /usr/lib/cockpit/cockpit-ws /usr/libexec/cockpit-ws 447 if test -x $p 448 set cockpit_ws_bin $p 449 break 450 end 451end 452 453if test -n "$cockpit_ws_bin" 454 if not pgrep -f "cockpit-ws" >/dev/null 455 # Set a dev password so PAM auth works (use vault COCKPIT_PASSWORD if set) 456 set -l cockpit_pass (test -n "$COCKPIT_PASSWORD"; and echo $COCKPIT_PASSWORD; or echo "aesthetic") 457 echo "me:$cockpit_pass" | sudo chpasswd 2>/dev/null 458 sudo $cockpit_ws_bin --no-tls --port=9090 >/tmp/cockpit-ws.log 2>&1 & 459 disown 460 log_ok "Cockpit started → http://localhost:9090 (login: me / $cockpit_pass)" 461 else 462 log_ok "Cockpit already running" 463 end 464else 465 log_warn "Cockpit not installed — skipping (rebuild container to add it)" 466end 467 468log_step "PHASE 5: Environment setup" 469# Ensure the envs directory exists and is accessible (fallback if mount fails) 470if not test -d /home/me/envs 471 log_info "Creating missing /home/me/envs directory and linking to .devcontainer/envs" 472 mkdir -p /home/me/envs 473 ln -sf /workspaces/aesthetic-computer/.devcontainer/envs/* /home/me/envs/ 474end 475 476if test -d /home/me/envs 477 source /home/me/envs/load_envs.fish 478 load_envs # Load devcontainer envs conditionally. 479 echo "🔧 Environment variables loaded from devcontainer.env" 480end 481 482# Set environment variables to prevent ETXTBSY errors and disable telemetry 483set -gx NETLIFY_CLI_TELEMETRY_DISABLED 1 484set -gx NODE_DISABLE_COMPILE_CACHE 1 485 486set -gx TERM xterm-256color 487 488# Create xdg-open wrapper to open URLs on Windows host from dev container 489if not test -f /usr/local/bin/xdg-open 490 echo "🌐 Creating xdg-open wrapper for host browser..." 491 printf '#!/bin/bash\n"\$BROWSER" "\$@"\n' | sudo tee /usr/local/bin/xdg-open >/dev/null 492 sudo chmod +x /usr/local/bin/xdg-open 493end 494 495# Start dbus-run-session for the keryring and execute the command passed to the script 496# dbus-run-session -- sh -c "eval \$(echo \$DBUS_SESSION_BUS_ADDRESS); exec $argv" 497 498# Send a welcome message! 499toilet "Aesthetic Computer" -f future | lolcat -x -r 500 501# Go to the user's directory. 502cd /home/me 503 504log_step "PHASE 6: SSL certificates" 505ensure_ssl_dev_certs 506 507log_step "PHASE 7: GitHub authentication" 508# Login to Github - use GH_TOKEN from vault if available 509set -l gh_authenticated 1 510if not gh auth status >/dev/null 2>&1 511 if test -n "$GH_TOKEN" 512 log_info "Authenticating to GitHub using GH_TOKEN..." 513 echo $GH_TOKEN | gh auth login --with-token 514 if gh auth status >/dev/null 2>&1 515 log_ok "GitHub authentication successful" 516 else 517 log_error "GitHub authentication failed" 518 log_warn "Continuing without GitHub auth; vault/git operations may be limited." 519 set gh_authenticated 0 520 end 521 else 522 log_warn "Not logged into GitHub and no GH_TOKEN available." 523 log_warn "Continuing startup without GitHub auth." 524 set gh_authenticated 0 525 end 526else 527 log_ok "Already authenticated to GitHub" 528end 529 530log_step "PHASE 8: Git configuration" 531if test -n "$GIT_USER_EMAIL" 532 git config --global user.email $GIT_USER_EMAIL 533 log_info "Set git user email to: $GIT_USER_EMAIL" 534end 535 536if test -n "$GIT_USER_NAME" 537 git config --global user.name $GIT_USER_NAME 538 log_info "Set git user name to: $GIT_USER_NAME" 539end 540 541# Add aesthetic-computer as the "safe" directory. 542git config --global --add safe.directory /home/me/aesthetic-computer 543 544# Set rebase as default for pull operations. 545git config --global pull.rebase true 546 547# Disable GPG signing to prevent commit issues in dev environment 548git config --global commit.gpgsign false 549 550# Make sure git is setup and authorized for making commits via `gh`. 551if test $gh_authenticated -eq 1 552 gh auth setup-git 553else 554 log_warn "Skipping 'gh auth setup-git' because GitHub auth is unavailable." 555end 556 557# Ensure GPG signing is disabled at both global and local levels (GitHub CLI might re-enable it) 558git config --global commit.gpgsign false 559cd /home/me/aesthetic-computer 560git config --local commit.gpgsign false 561git config --local user.signingkey "" 562echo "🔓 GPG signing disabled for commits" 563 564# Disable Netlify CLI telemetry to prevent ETXTBSY errors 565echo "Disabling Netlify CLI telemetry..." 566cd /home/me/aesthetic-computer/system && netlify --telemetry-disable 2>/dev/null || echo "Netlify telemetry disable completed" 567 568# Add aesthetic.local and sotce.local to /etc/hosts if they don't already exist 569if not grep -q "aesthetic.local" /etc/hosts 570 echo "127.0.0.1 aesthetic.local" | sudo tee -a /etc/hosts 571end 572 573if not grep -q "sotce.local" /etc/hosts 574 echo "127.0.0.1 sotce.local" | sudo tee -a /etc/hosts 575end 576 577log_step "PHASE 9: Vault setup" 578# Apply the 'vault' credentials to the mounted aesthetic-computer volume, and make sure it exists. 579if test -d /home/me/aesthetic-computer 580 if not test -d /home/me/aesthetic-computer/aesthetic-computer-vault 581 log_info "Cloning vault repository..." 582 gh repo clone whistlegraph/aesthetic-computer-vault /home/me/aesthetic-computer/aesthetic-computer-vault 583 cd /home/me/aesthetic-computer/aesthetic-computer-vault 584 log_info "Running devault.fish..." 585 sudo fish devault.fish 586 587 # Load environment variables after initial vault setup 588 if test -d /home/me/envs 589 source /home/me/envs/load_envs.fish 590 load_envs # Load envs after initial vault setup 591 log_ok "Environment variables loaded after initial vault setup" 592 end 593 else 594 cd /home/me/aesthetic-computer/aesthetic-computer-vault 595 log_info "Pulling latest vault..." 596 git pull 597 sudo fish devault.fish 598 log_ok "Vault mounted." 599 end 600 601 # Reload environment variables after vault is mounted 602 if test -d /home/me/envs 603 source /home/me/envs/load_envs.fish 604 load_envs # Reload envs after vault mount 605 log_ok "Environment variables reloaded after vault mount" 606 end 607 608 # Setup SSH keys from vault (only if not already set up) 609 set -l vault_ssh /home/me/aesthetic-computer/aesthetic-computer-vault/home/.ssh 610 if test -d $vault_ssh 611 # Only copy if id_rsa doesn't exist yet (first time setup) 612 if not test -f /home/me/.ssh/id_rsa 613 # Ensure .ssh directory exists with correct ownership and permissions 614 sudo mkdir -p /home/me/.ssh 615 sudo chown -R me:me /home/me/.ssh 2>/dev/null 616 sudo chmod 700 /home/me/.ssh 2>/dev/null 617 618 cp -f $vault_ssh/* /home/me/.ssh/ 2>/dev/null 619 chmod 700 /home/me/.ssh 2>/dev/null 620 chmod 600 /home/me/.ssh/id_rsa 2>/dev/null 621 chmod 644 /home/me/.ssh/id_rsa.pub 2>/dev/null 622 chmod 600 /home/me/.ssh/config 2>/dev/null 623 chmod 600 /home/me/.ssh/aesthetic_pds 2>/dev/null 624 chmod 644 /home/me/.ssh/aesthetic_pds.pub 2>/dev/null 625 log_ok "SSH keys restored from vault" 626 else 627 log_info "SSH keys already exist, skipping vault copy" 628 end 629 end 630 631 # Setup Copilot CLI config from vault (if volume is empty but vault has backup) 632 set -l vault_copilot /home/me/aesthetic-computer/aesthetic-computer-vault/home/.copilot 633 if test -d $vault_copilot 634 # Only restore if volume mount is empty (no config.json) 635 if not test -f /home/me/.copilot/config.json 636 mkdir -p /home/me/.copilot 637 cp -f $vault_copilot/config.json /home/me/.copilot/ 2>/dev/null 638 log_ok "Copilot CLI config restored from vault" 639 else 640 log_info "Copilot CLI config already exists (using volume data)" 641 end 642 end 643else 644 log_error "Vault unmounted! /home/me/aesthetic-computer not found" 645end 646 647log_step "PHASE 10: Fixing permissions" 648# Fix all permissions AFTER vault setup (vault copies files as root with sudo) 649log_info "Fixing permissions after vault setup..." 650 651# First, ensure the home directory itself is owned by me (critical for .emacs-logs etc) 652sudo chown me:me /home/me 2>/dev/null 653log_ok "Fixed ownership of /home/me" 654 655# Create .emacs-logs directory if it doesn't exist 656mkdir -p /home/me/.emacs-logs 2>/dev/null 657log_ok "Ensured /home/me/.emacs-logs exists" 658 659# Fix fish config permissions (vault may have overwritten with root-owned files) 660log_info "Fixing fish config permissions..." 661ensure_fish_config_permissions 662 663# Fix SSH directory permissions (use sudo to fix ownership if needed) 664if test -d /home/me/.ssh 665 if not test -O /home/me/.ssh 666 # SSH dir owned by root (probably from vault setup), fix ownership 667 sudo chown -R me:me /home/me/.ssh 2>/dev/null 668 log_ok "Fixed SSH directory ownership" 669 end 670 chmod 700 /home/me/.ssh 2>/dev/null 671 chmod 600 /home/me/.ssh/* 2>/dev/null 672 chmod 644 /home/me/.ssh/*.pub 2>/dev/null 673 log_ok "Fixed permissions for /home/me/.ssh" 674end 675 676# Fix Copilot CLI directory permissions (volume mount may have root ownership) 677if test -d /home/me/.copilot 678 sudo chown -R me:me /home/me/.copilot 2>/dev/null 679 sudo chmod 700 /home/me/.copilot 2>/dev/null 680 # Ensure pkg directory exists and is writable for package extraction 681 mkdir -p /home/me/.copilot/pkg 2>/dev/null 682 chmod 755 /home/me/.copilot/pkg 2>/dev/null 683 sudo chmod 600 /home/me/.copilot/config.json 2>/dev/null 684 echo "✅ Fixed permissions for /home/me/.copilot (Copilot CLI config)" 685end 686 687# Fix Claude/Codex config directory permissions after bind mounts are attached. 688# On Linux hosts, these mounts keep host ownership, so UID remapping is the main 689# fix; this container-side pass normalizes modes when ownership is already writable. 690for dir in /home/me/.claude /home/me/.codex 691 if test -d $dir 692 sudo chown -R me:me $dir 2>/dev/null 693 chmod 700 $dir 2>/dev/null 694 find $dir -type d -exec chmod 700 {} + 2>/dev/null 695 find $dir -type f -exec chmod 600 {} + 2>/dev/null 696 echo "✅ Fixed permissions for $dir" 697 end 698end 699 700if test -f /home/me/.claude.json 701 sudo chown me:me /home/me/.claude.json 2>/dev/null 702 chmod 600 /home/me/.claude.json 2>/dev/null 703 echo "✅ Fixed permissions for /home/me/.claude.json" 704end 705 706# Fix VS Code extension SecretStorage persistence paths. 707for dir in /home/me/.config/Code/User/globalStorage /home/me/.config/Code/User/workspaceStorage 708 if test -d $dir 709 sudo chown -R me:me $dir 2>/dev/null 710 find $dir -type d -exec chmod 700 {} + 2>/dev/null 711 find $dir -type f -exec chmod 600 {} + 2>/dev/null 712 echo "✅ Fixed permissions for $dir" 713 end 714end 715 716if test -d /home/me/.local/share/keyrings 717 sudo chown -R me:me /home/me/.local/share/keyrings 2>/dev/null 718 chmod 700 /home/me/.local/share/keyrings 2>/dev/null 719 find /home/me/.local/share/keyrings -type f -exec chmod 600 {} + 2>/dev/null 720 echo "✅ Fixed permissions for /home/me/.local/share/keyrings" 721end 722 723# --- GPG agent: cache passphrase for the entire container lifetime --- 724mkdir -p /home/me/.gnupg 2>/dev/null 725chmod 700 /home/me/.gnupg 726printf "allow-loopback-pinentry\npinentry-program /usr/sbin/pinentry-curses\ndefault-cache-ttl 999999\nmax-cache-ttl 999999\n" > /home/me/.gnupg/gpg-agent.conf 727gpgconf --reload gpg-agent 2>/dev/null 728log_ok "GPG agent configured (passphrase cached for container lifetime)" 729 730cd /home/me/aesthetic-computer/aesthetic-computer-vault 731git pull 732 733# Function to check and install npm dependencies in a directory 734set -g NODE_DEPS_CHECK_SCRIPT /workspaces/aesthetic-computer/.devcontainer/scripts/check-node-deps.mjs 735 736function verify_npm_versions 737 set -l dir $argv[1] 738 set -l dir_name (basename $dir) 739 740 if not test -f $NODE_DEPS_CHECK_SCRIPT 741 return 742 end 743 744 if not test -f $dir/package.json 745 return 746 end 747 748 if not test -d $dir/node_modules 749 return 750 end 751 752 log_cmd node $NODE_DEPS_CHECK_SCRIPT $dir 753 set -l check_status $status 754 755 if test $check_status -ne 0 756 echo "♻️ Resyncing dependencies in $dir_name to match package.json versions..." 757 cd $dir 758 log_cmd npm ci --no-fund --no-audit 759 if test $status -ne 0 760 echo "⚠️ npm ci failed in $dir_name, falling back to npm install" 761 log_cmd npm install --no-fund --no-audit 762 end 763 end 764end 765 766# Function to check and fix esbuild architecture mismatches 767function fix_esbuild_architecture 768 set -l dir $argv[1] 769 set -l dir_name (basename $dir) 770 771 # Check if this directory has esbuild installed 772 if test -d $dir/node_modules/@esbuild 773 set -l arch (uname -m) 774 set -l expected_esbuild 775 776 # Determine expected esbuild platform package 777 if test "$arch" = "x86_64" 778 set expected_esbuild "linux-x64" 779 else if test "$arch" = "aarch64" 780 set expected_esbuild "linux-arm64" 781 else 782 return 0 # Unknown architecture, skip 783 end 784 785 # Check what's actually installed 786 set -l installed_arch (ls $dir/node_modules/@esbuild 2>/dev/null | grep -E "^linux-") 787 788 if test -n "$installed_arch"; and test "$installed_arch" != "$expected_esbuild" 789 echo "🔧 Wrong esbuild architecture in $dir_name: $installed_arch (need $expected_esbuild)" 790 echo " Reinstalling dependencies to fix..." 791 cd $dir 792 rm -rf node_modules package-lock.json 793 log_cmd npm install --no-fund --no-audit 794 if test $status -eq 0 795 echo "✅ Fixed esbuild architecture in $dir_name" 796 else 797 echo "⚠️ Failed to fix esbuild in $dir_name" 798 end 799 end 800 end 801end 802 803function install_npm_deps 804 set -l dir $argv[1] 805 set -l dir_name (basename $dir) 806 807 if test -f $dir/package.json 808 if not test -d $dir/node_modules || not count $dir/node_modules/* >/dev/null 2>/dev/null 809 echo "📦 Installing dependencies in $dir_name..." 810 cd $dir 811 log_cmd npm ci --no-fund --no-audit 812 if test $status -ne 0 813 echo "⚠️ Failed to install dependencies in $dir_name, trying npm install..." 814 log_cmd npm install --no-fund --no-audit 815 end 816 else 817 echo "$dir_name already has node_modules" 818 # Check for architecture mismatches even if node_modules exists 819 fix_esbuild_architecture $dir 820 end 821 verify_npm_versions $dir 822 end 823end 824 825log_step "PHASE 11: NPM dependencies" 826# Check and install dependencies in key directories 827cd /home/me/aesthetic-computer 828 829# Install root dependencies first 830if not test -d /home/me/aesthetic-computer/node_modules || not count /home/me/aesthetic-computer/node_modules/* >/dev/null 831 log_info "Installing root dependencies..." 832 log_cmd npm install -g npm@latest --no-fund --no-audit 833 log_cmd npm ci --no-fund --no-audit 834else 835 log_ok "Root directory already has node_modules" 836end 837 838log_info "Verifying npm versions..." 839verify_npm_versions /home/me/aesthetic-computer 840 841# Install dependencies in critical subdirectories (archive intentionally excluded) 842set -l critical_dirs system session-server vscode-extension nanos daemon utilities shared 843 844log_info "Installing dependencies in critical directories..." 845for dir in $critical_dirs 846 if test -d /home/me/aesthetic-computer/$dir 847 log_info "Processing $dir..." 848 install_npm_deps /home/me/aesthetic-computer/$dir 849 end 850end 851 852# Run the comprehensive install script for any remaining directories 853log_info "Running comprehensive install script for remaining directories..." 854pushd /home/me/aesthetic-computer 855log_cmd npm run install:everything-else 856popd 857 858log_step "PHASE 12: Final setup" 859# Make sure this user owns the emacs directory. 860sudo chown -R me:me ~/.emacs.d 861 862# Link the prompts directory to VSCode User config 863mkdir -p ~/.config/Code/User 864rm -rf ~/.config/Code/User/prompts 865ln -s /home/me/aesthetic-computer/prompts ~/.config/Code/User/prompts 866log_ok "Prompts directory linked to VSCode User config" 867 868# Link the modes directory to .github for VSCode chatmodes 869rm -rf /home/me/aesthetic-computer/.github 870ln -s /home/me/aesthetic-computer/modes /home/me/aesthetic-computer/.github 871log_ok "Modes directory linked to .github for VSCode chatmodes" 872 873# Source the devcontainer config to load AC development functions 874source /workspaces/aesthetic-computer/.devcontainer/config.fish 875log_ok "AC development functions loaded (ac-pack, ac-unpack, etc.)" 876 877# Copy feed secrets from vault to environment (if vault exists) 878if test -f /workspaces/aesthetic-computer/aesthetic-computer-vault/feed/.env 879 log_info "Loading feed system environment variables from vault..." 880 # Copy to devcontainer envs directory for persistence 881 cp /workspaces/aesthetic-computer/aesthetic-computer-vault/feed/.env /home/me/envs/feed.env 882 # Source it globally for the session 883 for line in (cat /workspaces/aesthetic-computer/aesthetic-computer-vault/feed/.env | grep -v '^#' | grep '=') 884 set -gx (string split '=' $line) 885 end 886 log_ok "Feed environment variables loaded" 887else 888 echo "⚠️ Feed vault not found - skipping feed environment setup" 889end 890 891# Set port 8888 to public in Codespaces (if applicable) 892if test -f /workspaces/aesthetic-computer/.devcontainer/scripts/set-port-public.fish 893 log_cmd fish /workspaces/aesthetic-computer/.devcontainer/scripts/set-port-public.fish 894end 895 896# Create .waiter file to signal container is ready (moved from postAttachCommand to avoid terminal popup in Codespaces) 897sudo touch /home/me/.waiter 898sudo chmod 777 /home/me/.waiter 899sudo chmod +w /home/me 900echo "✅ Container ready signal created (.waiter)" 901 902# NOTE: Emacs daemon is NOT pre-started here. The `aesthetic` function 903# (called by the VS Code "💻 Aesthetic" task) unconditionally kills any 904# running daemon and starts fresh via `ensure-emacs-daemon-ready`. 905# Pre-starting here caused a race condition: entry.fish would start a 906# daemon, then the VS Code task would immediately kill it and start 907# another, wasting resources and causing load spikes that made the 908# second daemon unresponsive to the crash monitor. 909log_step "PHASE 12b: Emacs daemon (deferred to VS Code task)" 910log_info "Emacs daemon start deferred - will be started by 'aesthetic' function" 911 912# 🩸 Setup SSH tunnel for CDP (Chrome DevTools Protocol) to host 913# This allows artery-tui to control VS Code on the host machine 914if test -n "$HOST_IP"; or test (uname -s) != "Linux" 915 # Kill any existing CDP tunnels 916 pkill -f "ssh.*9333.*host.docker.internal" 2>/dev/null 917 918 # Create tunnel in background (port 9333 to avoid conflicts with svchost.exe on 9222) 919 start_cdp_tunnel 920 if test $status -eq 0 921 echo "🩸 CDP tunnel established (localhost:9333 → host:9333)" 922 else 923 echo "⚠️ CDP tunnel failed (artery may not work)" 924 end 925end 926 927# 🧊 Start TURN server for WebRTC relay (required for UDP in Docker) 928if which turnserver >/dev/null 2>&1 929 pkill -f "turnserver" 2>/dev/null 930 sleep 0.5 931 # Get host LAN IP from vault/machines.json or use default 932 set -l HOST_LAN_IP "192.168.1.127" 933 set -l HOST_LAN_IP_SOURCE "default" 934 if test -f /workspaces/aesthetic-computer/aesthetic-computer-vault/machines.json 935 set -l detected_ip (cat /workspaces/aesthetic-computer/aesthetic-computer-vault/machines.json 2>/dev/null | jq -r '.["aesthetic-mac"].lan_ip // empty' 2>/dev/null) 936 if test -n "$detected_ip" 937 set HOST_LAN_IP $detected_ip 938 set HOST_LAN_IP_SOURCE "vault" 939 end 940 end 941 log_info "TURN host IP: $HOST_LAN_IP (source: $HOST_LAN_IP_SOURCE)" 942 echo $HOST_LAN_IP > /tmp/host-lan-ip 943 turnserver -c /workspaces/aesthetic-computer/.devcontainer/turnserver.conf --external-ip=$HOST_LAN_IP >> $ENTRY_LOG_REAL 2>&1 & 944 disown 945 log_ok "TURN server started (localhost:3478, external-ip: $HOST_LAN_IP)" 946else 947 log_warn "coturn not installed, UDP may not work across networks" 948end 949 950# echo "Initializing 📋 Clipboard Service" | lolcat -x -r 951 952# ❤️‍🔥 953# TODO: This may not be the best method because cdocker aesthetic needs to be 954# running in the user environment that has the clipboard. 955 956# Run the isomorphic_copy clipboard on the host. 957# Make sure the host allows ssh access from its own private key... `ssh-copy-id -i ~/.ssh/id_rsa.pub $USER@localhost` 958# ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $HOST_USER@172.17.0.1 959 960# ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $HOST_USER@172.17.0.1 "cdocker aesthetic" 961 962# 🔍 Ensure Devcontainer Status Server is still running (it was started early) 963log_info "Checking Devcontainer Status Server..." 964if pgrep -f "devcontainer-status" >/dev/null 965 log_ok "Status Server still running on http://127.0.0.1:7890" 966else if test -f /workspaces/aesthetic-computer/artery/devcontainer-status.mjs 967 log_warn "Status Server died, restarting..." 968 nohup node /workspaces/aesthetic-computer/artery/devcontainer-status.mjs --server >/tmp/devcontainer-status.log 2>&1 & 969 disown 970 log_ok "Status Server restarted on http://127.0.0.1:7890" 971end 972 973log "════════════════════════════════════════════════════════════════" 974log "🎉 ENTRY.FISH COMPLETED SUCCESSFULLY" 975log "════════════════════════════════════════════════════════════════" 976log_info "End time: "(date -Iseconds) 977log_info "Log file: $ENTRY_LOG_REAL" 978 979# Auto-launch is handled by the VS Code task (💻 Aesthetic) which runs on folder open 980# The task calls aesthetic-launch.sh which properly launches the emacs client 981# Background launch from entry.fish doesn't work because emacsclient -nw needs an interactive terminal 982log_info "Container setup complete - VS Code task will launch aesthetic platform"