#!/usr/bin/env bash # ============================================================================= # osvauco-opax-boot.sh — OSVauco OPAX session-starter # Bruk: source ~/OSVauco/scripts/osvauco-opax-boot.sh # NB: Må sources (ikke bash) for PROMPT_COMMAND + opax_logg_slutt. # Standalone avslutt: bash ~/OSVauco/scripts/opax-logg-slutt.sh # ============================================================================= OSVAUCO_DIR="$HOME/OSVauco" ROADMAP="$OSVAUCO_DIR/docs/VAUCO_OS_ROADMAP.md" TODO="$OSVAUCO_DIR/docs/TODO.md" SESSION_LOG="$OSVAUCO_DIR/docs/OSVAUCO_OPAX_SESSION_LOG.md" STATE_FILE="$OSVAUCO_DIR/.gdrive-mirror-state" BASHRC="$HOME/.bashrc" GREEN="$(tput setaf 2 || true)" RED="$(tput setaf 1 || true)" YELLOW="$(tput setaf 3 || true)" CYAN="$(tput setaf 6 || true)" BOLD="$(tput bold || true)" DIM="\033[2m" NC="$(tput sgr0 || true)" OK="${GREEN}[OK]${NC}" WARN="${YELLOW}[!!]${NC}" FAIL="${RED}[XX]${NC}" SESSION_ID="$(date '+%Y%m%d-%H%M%S')" # ============================================================================= # ALIAS + PROMPT_COMMAND AUTO-INJECT i ~/.bashrc (idempotent) # ============================================================================= _OSVAUCO_ALIAS_MARKER="# [OSVauco] auto-injected aliases" if ! grep -qF "$_OSVAUCO_ALIAS_MARKER" "$BASHRC" 2>/dev/null; then cat >> "$BASHRC" << 'ALIASES' # [OSVauco] auto-injected aliases alias opax='source ~/OSVauco/scripts/osvauco-opax-boot.sh' alias opax-logg-slutt='bash ~/OSVauco/scripts/opax-logg-slutt.sh' alias mirror-sync='bash ~/OSVauco/scripts/sync-gdrive-mirror.sh' alias cost-audit='bash ~/OSVauco/scripts/cost-audit.sh' alias roadmap='cat ~/OSVauco/docs/VAUCO_OS_ROADMAP.md' alias session-log='cat ~/OSVauco/docs/OSVAUCO_OPAX_SESSION_LOG.md' ALIASES _ALIAS_INJECTED=true else _ALIAS_INJECTED=false fi # Last aliases inn i nåværende shell uansett alias opax='source ~/OSVauco/scripts/osvauco-opax-boot.sh' alias opax-logg-slutt='opax_logg_slutt' alias mirror-sync='bash ~/OSVauco/scripts/sync-gdrive-mirror.sh' alias cost-audit='bash ~/OSVauco/scripts/cost-audit.sh' alias roadmap='cat ~/OSVauco/docs/VAUCO_OS_ROADMAP.md' alias session-log='cat ~/OSVauco/docs/OSVAUCO_OPAX_SESSION_LOG.md' # ============================================================================= # PROMPT_COMMAND — logger hver terminal-kommando med tidsstempel til session-log # ============================================================================= export OSVAUCO_SESSION_LOG="$SESSION_LOG" export OSVAUCO_SESSION_ID="$SESSION_ID" _opax_last_cmd='' trap '_opax_last_cmd=$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//")' DEBUG _opax_log_cmd() { local exit_code=$? local cmd="$_opax_last_cmd" [[ -z "$cmd" ]] && return [[ "$cmd" == _opax_* ]] && return [[ "$cmd" == "trap "* ]] && return local ts ts=$(date '+%H:%M:%S') local status_marker [[ $exit_code -eq 0 ]] && status_marker="✔" || status_marker="✘[$exit_code]" printf ' %s %s %s\n' "$ts" "$status_marker" "$cmd" >> "${OSVAUCO_SESSION_LOG}" 2>/dev/null || true _opax_last_cmd='' } if [[ "${PROMPT_COMMAND}" != *"_opax_log_cmd"* ]]; then PROMPT_COMMAND="_opax_log_cmd${PROMPT_COMMAND:+; $PROMPT_COMMAND}" fi export PROMPT_COMMAND # ============================================================================= # Load nvm # ============================================================================= export NVM_DIR="$HOME/.nvm" [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" if ! command -v gemini &>/dev/null && [[ -d "$NVM_DIR" ]]; then NVM_DEFAULT=$(nvm version default 2>/dev/null || true) [[ -n "$NVM_DEFAULT" ]] && nvm use "$NVM_DEFAULT" &>/dev/null || true fi clear cat << 'BANNER' ============================================================ O S V A U C O · O P A X S E S S I O N ============================================================ BANNER printf " Session : ${CYAN}${BOLD}%s${NC}\n" "$SESSION_ID" printf " Project : %s\n" "${PROJECT_ID:-propane-will-491900-m5}" printf " $(date '+%Y-%m-%d %H:%M %Z')\n" printf " ----------------------------------------------------\n\n" # ============================================================================= # SECTION 1: AUTH # ============================================================================= printf "${BOLD}${CYAN} [ AUTH ]${NC}\n" if [[ -f "$OSVAUCO_DIR/.env" ]]; then set -o allexport; source "$OSVAUCO_DIR/.env"; set +o allexport printf " $OK .env ${DIM}PROJECT_ID=${PROJECT_ID}${NC}\n" else printf " $FAIL .env MISSING ${YELLOW}cp .env.example .env${NC}\n" fi if gcloud auth print-access-token >/dev/null 2>&1; then ACCOUNT=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null) printf " $OK gcloud ${DIM}%s${NC}\n" "$ACCOUNT" else printf " $FAIL gcloud ${YELLOW}gcloud auth login --no-launch-browser${NC}\n" fi if gcloud auth application-default print-access-token >/dev/null 2>&1; then printf " $OK ADC ${DIM}Application Default Credentials OK${NC}\n" else printf " $WARN ADC ${YELLOW}gcloud auth application-default login${NC}\n" fi if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then GH_USER=$(gh api user --jq .login 2>/dev/null || echo "ukjent") printf " $OK GitHub CLI ${DIM}gh → %s${NC}\n" "$GH_USER" else printf " $WARN GitHub CLI ${YELLOW}gh auth login (valgfritt)${NC}\n" fi if command -v gemini &>/dev/null; then GEMINI_VER=$(gemini --version 2>/dev/null || echo "ukjent") printf " $OK Gemini CLI ${DIM}%s${NC}\n" "$GEMINI_VER" else printf " $WARN Gemini CLI ${YELLOW}npm install -g @google/gemini-cli${NC}\n" fi if [[ "$_ALIAS_INJECTED" == true ]]; then printf " $OK Aliases ${DIM}Lagt til i ~/.bashrc (aktiv nå)${NC}\n" else printf " $OK Aliases ${DIM}Allerede i ~/.bashrc${NC}\n" fi printf " $OK Terminal-logging ${DIM}PROMPT_COMMAND aktiv — loggfører alle kommandoer${NC}\n" printf "\n" # ============================================================================= # SECTION 2: OPAX HEALTH # Bruker /health (autentisert) — appen har ikke /ping # ============================================================================= printf "${BOLD}${CYAN} [ OPAX HEALTH ]${NC}\n" HEALTH_URL="https://opax.vauco.no/health" ID_TOKEN=$(gcloud auth print-identity-token 2>/dev/null || echo "") if [[ -n "$ID_TOKEN" ]] && curl -fsS --max-time 5 \ -H "Authorization: Bearer ${ID_TOKEN}" \ "$HEALTH_URL" >/dev/null 2>&1; then printf " $OK opax.vauco.no ${DIM}/health — {\"status\":\"ok\"}${NC}\n" else HTTP_CODE=$(curl -o /dev/null -s -w "%{http_code}" --max-time 5 "$HEALTH_URL" 2>/dev/null || echo "000") case "$HTTP_CODE" in 403) printf " $WARN opax.vauco.no ${YELLOW}Oppe men krever auth (403) — IAP konfigureres i Phase 5${NC}\n" ;; 000) printf " $FAIL opax.vauco.no ${RED}NEDE — ingen respons (sjekk Cloud Run / DNS)${NC}\n" ;; *) printf " $WARN opax.vauco.no ${YELLOW}HTTP %s — sjekk Cloud Run${NC}\n" "$HTTP_CODE" ;; esac fi printf "\n" # ============================================================================= # SECTION 3: REPO SYNC + GDRIVE MIRROR # ============================================================================= printf "${BOLD}${CYAN} [ REPO SYNC ]${NC}\n" LOCAL_SHA=$(git -C "$OSVAUCO_DIR" rev-parse --short HEAD 2>/dev/null || echo "ukjent") LOCAL_BRANCH=$(git -C "$OSVAUCO_DIR" branch --show-current 2>/dev/null || echo "ukjent") REMOTE_SHA=$(git -C "$OSVAUCO_DIR" ls-remote origin refs/heads/main 2>/dev/null | cut -c1-7 || echo "") if [[ -z "$REMOTE_SHA" ]]; then printf " $WARN GitHub HEAD ${YELLOW}Kunne ikke nå GitHub (offline?)${NC}\n" printf " ${DIM}Lokal: %s @ %s${NC}\n" "$LOCAL_SHA" "$LOCAL_BRANCH" elif [[ "$LOCAL_SHA" == "$REMOTE_SHA" ]]; then printf " $OK GitHub ≡ Lokal ${DIM}HEAD %s @ %s — ingen diff${NC}\n" "$LOCAL_SHA" "$LOCAL_BRANCH" else printf " $WARN GitHub ≠ Lokal ${YELLOW}GitHub: %s │ Lokal: %s @ %s${NC}\n" "$REMOTE_SHA" "$LOCAL_SHA" "$LOCAL_BRANCH" printf " ${DIM}Kjør: git pull origin main${NC}\n" fi printf "\n" printf "${BOLD}${CYAN} [ GDRIVE MIRROR ]${NC}\n" if [[ -f "$STATE_FILE" ]]; then LAST_SYNC=$(grep '^LAST_SYNC=' "$STATE_FILE" | cut -d= -f2-) LAST_SHA=$(grep '^LAST_SHA=' "$STATE_FILE" | cut -d= -f2-) SYNC_EPOCH=$(date -d "${LAST_SYNC}" '+%s' 2>/dev/null \ || date -j -f '%Y-%m-%dT%H:%M %Z' "${LAST_SYNC}" '+%s' 2>/dev/null \ || echo 0) NOW_EPOCH=$(date '+%s') AGE_HOURS=$(( (NOW_EPOCH - SYNC_EPOCH) / 3600 )) AGE_MIN=$(( (NOW_EPOCH - SYNC_EPOCH) / 60 % 60 )) if [[ "$LAST_SHA" != "$LOCAL_SHA" ]]; then printf " $FAIL GDrive mirror ${RED}UTDATERT — SHA endret (%s → %s)${NC}\n" "$LAST_SHA" "$LOCAL_SHA" printf " ${YELLOW}Kjør: mirror-sync${NC}\n" elif [[ "$AGE_HOURS" -ge 12 ]]; then printf " $FAIL GDrive mirror ${RED}GAMMEL — %st %sm siden sist sync${NC}\n" "$AGE_HOURS" "$AGE_MIN" printf " ${YELLOW}Kjør: mirror-sync${NC}\n" elif [[ "$AGE_HOURS" -ge 8 ]]; then printf " $WARN GDrive mirror ${YELLOW}%st %sm siden sist sync (terskel 12t)${NC}\n" "$AGE_HOURS" "$AGE_MIN" printf " ${DIM}Vurder: mirror-sync${NC}\n" else printf " $OK GDrive mirror ${DIM}%s · HEAD %s${NC}\n" "$LAST_SYNC" "$LAST_SHA" fi else printf " $WARN GDrive mirror ${YELLOW}Aldri synkronisert — kjør: mirror-sync${NC}\n" fi printf "\n" # ============================================================================= # SECTION 4: NESTE OPPGAVE # ============================================================================= printf "${BOLD}${CYAN} [ NESTE OPPGAVE ]${NC}\n" if [[ -f "$ROADMAP" ]]; then NEXT_ROADMAP=$(awk '/^## NEXT/{f=1;next} f && /^## /{f=0} f && /^- \[ \]/{print;exit}' "$ROADMAP") if [[ -n "$NEXT_ROADMAP" ]]; then printf " ${GREEN}${BOLD}▶ ROADMAP NEXT:${NC}\n" printf " ${GREEN}%s${NC}\n" "$NEXT_ROADMAP" fi fi if [[ -f "$TODO" ]]; then TODO_ITEMS=$(grep -m3 '^- \[ \]' "$TODO" 2>/dev/null || true) if [[ -n "$TODO_ITEMS" ]]; then printf " ${YELLOW}${BOLD}▶ TODO:${NC}\n" while IFS= read -r line; do printf " ${YELLOW}%s${NC}\n" "$line" done <<< "$TODO_ITEMS" fi fi printf "\n" # ============================================================================= # SECTION 5: SESSION-LOGG START # ============================================================================= mkdir -p "$(dirname "$SESSION_LOG")" printf "${BOLD}${CYAN} [ SESSION ]${NC}\n" printf " Hva skal du jobbe med i dag?\n" printf " ${DIM}(skriv kort beskrivelse, trykk Enter)${NC}\n > " read -r SESSION_DESC [[ -z "$SESSION_DESC" ]] && SESSION_DESC="(ingen beskrivelse)" _OPAX_HEALTH="NEDE" if [[ -n "$ID_TOKEN" ]] && curl -fsS --max-time 3 \ -H "Authorization: Bearer ${ID_TOKEN}" \ "$HEALTH_URL" >/dev/null 2>&1; then _OPAX_HEALTH="OK" fi cat >> "$SESSION_LOG" << EOF --- ## Session: $SESSION_ID - Tid : $(date '+%Y-%m-%d %H:%M %Z') - Bruker : ${ACCOUNT:-ukjent} - OPAX : ${_OPAX_HEALTH} - Lokal : $LOCAL_SHA @ $LOCAL_BRANCH - Remote : ${REMOTE_SHA:-ukjent} - Mål : $SESSION_DESC ### Kommandologg EOF printf " $OK Logg startet ${DIM}→ docs/OSVAUCO_OPAX_SESSION_LOG.md${NC}\n" printf " ${DIM}Alle kommandoer loggføres automatisk med tidsstempel + exit-kode.${NC}\n\n" # ============================================================================= # QUICK REFERENCE # ============================================================================= printf "${DIM} ---------------------------------------------------${NC}\n" printf " ${CYAN}${BOLD}HURTIGKOMMANDOER${NC}\n" printf " ${DIM}opax${NC} → ny session (source boot på nytt)\n" printf " ${DIM}gemini${NC} → Gemini TUI (OPAX-MCP)\n" printf " ${DIM}cost-audit${NC} → bash scripts/cost-audit.sh\n" printf " ${DIM}roadmap${NC} → cat docs/VAUCO_OS_ROADMAP.md\n" printf " ${DIM}session-log${NC} → cat docs/OSVAUCO_OPAX_SESSION_LOG.md\n" printf " ${DIM}mirror-sync${NC} → bash scripts/sync-gdrive-mirror.sh\n" printf " ${DIM}opax-logg-slutt${NC} → avslutt og loggfør session\n" printf "${DIM} ---------------------------------------------------${NC}\n\n" # ============================================================================= # AVSLUTT-FUNKSJON # ============================================================================= opax_logg_slutt() { PROMPT_COMMAND="${PROMPT_COMMAND//_opax_log_cmd; /}" PROMPT_COMMAND="${PROMPT_COMMAND//_opax_log_cmd/}" printf "\n ${BOLD}${CYAN}Sesjonslogg — avslutt${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 - Gjort : $DONE_DESC - Uløst : $UNSOLVED - Slutt : $(date '+%Y-%m-%d %H:%M %Z') EOF printf " ${GREEN}[OK]${NC} Logg oppdatert → docs/OSVAUCO_OPAX_SESSION_LOG.md\n\n" } export -f opax_logg_slutt 2>/dev/null || true alias opax-logg-slutt='opax_logg_slutt' printf " ${DIM}Avslutt session → ${NC}${BOLD}opax-logg-slutt${NC}\n\n" # ============================================================================= # VALGFRI GEMINI-START # ============================================================================= read -r -p " Starte Gemini-CLI nå? [y/N]: " ANSWER case "$ANSWER" in y|Y) echo if ! command -v gemini &>/dev/null; then printf " ${RED}[XX]${NC} gemini ikke funnet.\n" else echo " [OSVauco] Starter Gemini-CLI fra ~/OSVauco..." cd "$OSVAUCO_DIR" gemini fi ;; *) echo echo " [OSVauco] OK — kjør 'gemini' når du vil. God session! 🚀" ;; esac