#!/usr/bin/env bash # ============================================================================= # boot.sh — OSVauco daily VM session-starter # # Bruk: source ~/OSVauco/scripts/boot.sh # Eller legg i ~/.bashrc: # [[ $- == *i* && -z "$OSVAUCO_BOOTED" ]] && source ~/OSVauco/scripts/boot.sh # ============================================================================= export OSVAUCO_BOOTED=1 OSVAUCO_DIR="${OSVAUCO_DIR:-$HOME/OSVauco}" HANDOFF="$OSVAUCO_DIR/docs/HANDOFF.md" ROADMAP="$OSVAUCO_DIR/docs/ROADMAP.md" MASTERPLAN="$OSVAUCO_DIR/docs/MASTERPLAN.md" RULEBOOK="$OSVAUCO_DIR/docs/AGENT_RULEBOOK.md" SESSION_LOG="$OSVAUCO_DIR/docs/OSVAUCO_OPAX_SESSION_LOG.md" # Locked values (matcher docs/AGENT_RULEBOOK.md) export GOOGLE_CLOUD_PROJECT="propane-will-491900-m5" export GOOGLE_CLOUD_LOCATION="europe-west1" export VERTEX_AI_LOCATION="europe-west1" export OSVAUCO_SERVICE="osvauco-agent" DIRECT_URL="https://osvauco-agent-357036551735.europe-west1.run.app" DOMAIN_URL="https://opax.vauco.no" GREEN="$(tput setaf 2 2>/dev/null || true)" RED="$(tput setaf 1 2>/dev/null || true)" YELLOW="$(tput setaf 3 2>/dev/null || true)" CYAN="$(tput setaf 6 2>/dev/null || true)" MAGENTA="$(tput setaf 5 2>/dev/null || true)" WHITE="$(tput setaf 7 2>/dev/null || true)" BOLD="$(tput bold 2>/dev/null || true)" DIM="$(tput dim 2>/dev/null || true)" NC="$(tput sgr0 2>/dev/null || true)" SESSION_ID="$(date '+%Y%m%d-%H%M%S')" export OSVAUCO_SESSION_ID="$SESSION_ID" export OSVAUCO_SESSION_START="$(date '+%Y-%m-%d %H:%M %Z')" ok() { printf " ${GREEN}✦${NC} %s\n" "$1"; } warn() { printf " ${YELLOW}⚠${NC} %s\n" "$1"; } fail() { printf " ${RED}✗${NC} %s\n" "$1"; } # ============================================================================= # HEADER — OS VAUCO # ============================================================================= clear printf "${CYAN}${BOLD}" cat << 'LOGO' ___ ____ __ __ _ _ _ ____ ___ / _ \/ ___| \ \ / /_ _| | | | | |/ ___|/ _ \ | | | \___ \ \ \ / / _` | | | | | | | | | | | | |_| |___) | \ V / (_| | |__| |_| | |___| |_| | \___/|____/ \_/ \__,_|____|\___/ \____|\___/ LOGO printf "${NC}${DIM} Vauco OS · Operasjonsplatform · %s${NC}\n" "$(date '+%Y-%m-%d %H:%M')" printf "${DIM} ──────────────────────────────────────────────────────${NC}\n\n" # ============================================================================= # 1. AUTH # ============================================================================= printf "${BOLD}${CYAN}[ AUTH ]${NC}\n" if ! gcloud auth print-access-token >/dev/null 2>&1; then warn "gcloud auth utløpt — kjører login (no-browser)..." gcloud auth login --no-launch-browser else ACCT=$(gcloud auth list --filter=status:ACTIVE --format='value(account)' 2>/dev/null | head -1) ok "gcloud auth ($ACCT)" fi ADC_FILE="$HOME/.config/gcloud/.osvauco-adc-renewed" NEED_ADC=0 if ! gcloud auth application-default print-access-token >/dev/null 2>&1; then NEED_ADC=1 elif [[ ! -f "$ADC_FILE" ]] || [[ $(($(date +%s) - $(stat -c %Y "$ADC_FILE" 2>/dev/null || echo 0))) -gt 28800 ]]; then NEED_ADC=1 fi if [[ $NEED_ADC -eq 1 ]]; then warn "ADC utløpt eller >8t — fornyer..." gcloud auth application-default login --no-launch-browser \ --scopes="https://www.googleapis.com/auth/cloud-platform" && touch "$ADC_FILE" else ok "ADC OK" fi # ============================================================================= # 2. PROJECT # ============================================================================= printf "${BOLD}${CYAN}[ PROJECT ]${NC}\n" CURRENT_PROJ=$(gcloud config get-value project 2>/dev/null) if [[ "$CURRENT_PROJ" != "$GOOGLE_CLOUD_PROJECT" ]]; then gcloud config set project "$GOOGLE_CLOUD_PROJECT" >/dev/null 2>&1 warn "Satt project → $GOOGLE_CLOUD_PROJECT" else ok "project = $GOOGLE_CLOUD_PROJECT" fi ok "region = $GOOGLE_CLOUD_LOCATION (Vertex EU)" # ============================================================================= # 3. REPO + GITHUB STATUS # ============================================================================= printf "${BOLD}${CYAN}[ REPO + GITHUB ]${NC}\n" if [[ -d "$OSVAUCO_DIR/.git" ]]; then cd "$OSVAUCO_DIR" BRANCH=$(git branch --show-current) git fetch --quiet origin 2>/dev/null && ok "git fetch OK" || warn "git fetch feilet (offline?)" # Pull if git pull --ff-only origin "$BRANCH" >/dev/null 2>&1; then ok "git pull OK (branch: $BRANCH)" else warn "git pull ikke fast-forward — sjekk 'git status'" fi # Ahead/behind AHEAD=$(git rev-list --count "origin/$BRANCH..HEAD" 2>/dev/null || echo "?") BEHIND=$(git rev-list --count "HEAD..origin/$BRANCH" 2>/dev/null || echo "?") if [[ "$AHEAD" == "0" && "$BEHIND" == "0" ]]; then ok "sync med origin/$BRANCH" else warn "ahead=$AHEAD behind=$BEHIND vs origin/$BRANCH" fi # Uncommitted DIRTY=$(git status --porcelain | wc -l) if [[ "$DIRTY" == "0" ]]; then ok "working tree clean" else warn "$DIRTY uncommitted endringer ('git status' for liste)" fi # Last commit LAST=$(git log -1 --format='%h %s (%cr)' 2>/dev/null) printf " ${DIM}last:${NC} %s\n" "$LAST" # gh CLI auth if command -v gh >/dev/null 2>&1; then if gh auth status >/dev/null 2>&1; then GH_USER=$(gh api user --jq '.login' 2>/dev/null || echo "?") ok "gh CLI auth ($GH_USER)" # Open PRs på denne branchen OPEN_PR=$(gh pr list --head "$BRANCH" --json number,title --jq '.[0] | "PR #\(.number): \(.title)"' 2>/dev/null) [[ -n "$OPEN_PR" ]] && printf " ${DIM}pr:${NC} %s\n" "$OPEN_PR" else warn "gh CLI ikke autentisert — kjør: gh auth login" fi else warn "gh CLI ikke installert — installer: sudo apt install gh" fi else fail "Repo ikke funnet på $OSVAUCO_DIR" fi # ============================================================================= # 4. LOCKED DEFS # ============================================================================= printf "${BOLD}${CYAN}[ LOCKED ]${NC}\n" printf " ${DIM}service=${NC}%s ${DIM}lb=${NC}34.98.77.173\n" "$OSVAUCO_SERVICE" printf " ${DIM}url=${NC}%s\n" "$DOMAIN_URL" printf " ${DIM}direct=${NC}%s\n" "$DIRECT_URL" # ============================================================================= # 5. NESTE OPPGAVE (matcher både "NESTE OPPGAVE" og "Neste oppgave") # ============================================================================= printf "${BOLD}${CYAN}[ NESTE OPPGAVE ]${NC}\n" if [[ -f "$HANDOFF" ]]; then NEXT=$(sed -n '/^##.*[Nn]este [Oo]ppgave/,/^## /p' "$HANDOFF" | sed '1d;$d' | sed '/^$/d' | head -12) if [[ -n "$NEXT" ]]; then printf "${GREEN}%s${NC}\n" "$NEXT" else warn "Ingen 'Neste oppgave'-seksjon funnet i HANDOFF.md" fi else fail "HANDOFF.md mangler: $HANDOFF" fi # ============================================================================= # 6. ALIASER / HOTKEYS # ============================================================================= alias pf='source $OSVAUCO_DIR/scripts/preflight.sh' alias hc='bash $OSVAUCO_DIR/scripts/health-check.sh' alias st='bash $OSVAUCO_DIR/scripts/smoke-test.sh' alias at='bash $OSVAUCO_DIR/scripts/acceptance-test.sh' alias opax='source $OSVAUCO_DIR/scripts/opax.sh' alias opax2='source $OSVAUCO_DIR/scripts/opax2.sh' alias ca='bash $OSVAUCO_DIR/scripts/cost-audit.sh' alias cl='bash $OSVAUCO_DIR/scripts/cost-lens.sh' alias cg='bash $OSVAUCO_DIR/scripts/cost-guard.sh' alias costs='bash $OSVAUCO_DIR/scripts/cost-lens.sh' alias ms='bash $OSVAUCO_DIR/scripts/sync-gdrive-mirror.sh' alias logg='bash $OSVAUCO_DIR/scripts/opax-logg-slutt.sh' alias rl='${PAGER:-less} $ROADMAP' alias mp='${PAGER:-less} $MASTERPLAN' alias ho='${PAGER:-less} $HANDOFF' alias rb='${PAGER:-less} $RULEBOOK' alias sl='${PAGER:-less} $SESSION_LOG' alias osv='cd $OSVAUCO_DIR' alias reboot-osv='unset OSVAUCO_BOOTED; source $OSVAUCO_DIR/scripts/boot.sh' alias ghs='gh pr list && gh issue list' # sol() — avslutt-funksjon sol() { printf "\n ${BOLD}${CYAN}Sesjonsavslutning${NC}\n" printf " Hva ble gjort? (LØST / ULØST)\n > "; read -r DONE_DESC [[ -z "$DONE_DESC" ]] && DONE_DESC="(ingen notat)" printf " Uløste problemer? (Enter for ingen)\n > "; read -r UNSOLVED [[ -z "$UNSOLVED" ]] && UNSOLVED="ingen" cat >> "$SESSION_LOG" << EOF ### Sesjonsavslutning $OSVAUCO_SESSION_ID - Start : $OSVAUCO_SESSION_START - Slutt : $(date '+%Y-%m-%d %H:%M %Z') - Gjort : $DONE_DESC - Uløst : $UNSOLVED EOF ok "Logg oppdatert" cd "$OSVAUCO_DIR" git add docs/OSVAUCO_OPAX_SESSION_LOG.md 2>/dev/null if ! git diff --cached --quiet; then git commit -m "chore(session): logg $OSVAUCO_SESSION_ID — $DONE_DESC" -q git push origin "$(git branch --show-current)" -q && ok "Pushet → GitHub" fi } export -f sol # ============================================================================= # 7. QUICK COMMANDS-TABELL # ============================================================================= printf "${DIM}────────────────────────────────────────────────────────────${NC}\n" printf "${BOLD}HOTKEYS${NC}\n" printf " %-8s %-22s %-8s %-22s\n" "opax" "Gemini 2.5 Pro TUI" "opax2" "Claude Opus 4.7 TUI" printf " %-8s %-22s %-8s %-22s\n" "pf" "preflight" "hc" "health-check" printf " %-8s %-22s %-8s %-22s\n" "st" "smoke-test" "at" "acceptance-test" printf " %-8s %-22s %-8s %-22s\n" "ca" "cost-audit" "cl" "cost-lens" printf " %-8s %-22s %-8s %-22s\n" "cg" "cost-guard" "costs" "cost-lens (alias)" printf " %-8s %-22s %-8s %-22s\n" "mp" "vis MASTERPLAN" "rl" "vis ROADMAP" printf " %-8s %-22s %-8s %-22s\n" "ho" "vis HANDOFF" "rb" "vis RULEBOOK" printf " %-8s %-22s %-8s %-22s\n" "sl" "vis SESSION_LOG" "logg" "manuell logg-slutt" printf " %-8s %-22s %-8s %-22s\n" "ghs" "gh PRs + issues" "ms" "mirror-sync (GDrive)" printf " %-8s %-22s %-8s %-22s\n" "osv" "cd ~/OSVauco" "sol" "avslutt + commit" printf " %-8s %-22s\n" "reboot-osv" "kjør boot.sh på nytt" printf "${DIM}────────────────────────────────────────────────────────────${NC}\n" # ============================================================================= # 8. NVM # ============================================================================= export NVM_DIR="$HOME/.nvm" [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" # ============================================================================= # 9. VALG: opax / opax2 / hopp over # ============================================================================= printf "\n${BOLD}Hvilken TUI vil du starte?${NC}\n" printf " ${CYAN}1${NC}) opax — Gemini 2.5 Pro (Vertex EU) ${DIM}[default]${NC}\n" printf " ${MAGENTA}2${NC}) opax2 — Claude Opus 4.7 (Vertex EU)\n" printf " ${DIM}3${NC}) hopp over (jobb i shell)\n" printf " Velg [1/2/3]: " read -r CHOICE case "${CHOICE:-1}" in 1|"") printf " ${GREEN}→ starter opax (Gemini 2.5 Pro)${NC}\n\n" source "$OSVAUCO_DIR/scripts/opax.sh" ;; 2) printf " ${MAGENTA}→ starter opax2 (Claude)${NC}\n\n" source "$OSVAUCO_DIR/scripts/opax2.sh" ;; *) printf " ${DIM}OK — shell ready. Kjør 'opax' eller 'opax2' når du er klar.${NC}\n\n" ;; esac