diff --git a/.github/workflows/backup-gdrive-nightly.yml b/.github/workflows/backup-gdrive-nightly.yml new file mode 100644 index 0000000..862f13e --- /dev/null +++ b/.github/workflows/backup-gdrive-nightly.yml @@ -0,0 +1,91 @@ +name: Nightly GDrive Backup + +# Kjører kl 03:00 UTC (05:00 CEST) hver natt + ved push til main +on: + schedule: + - cron: '0 3 * * *' + push: + branches: + - main + workflow_dispatch: # manuell trigger fra GitHub UI + +jobs: + backup: + name: Backup OSVauco → Google Drive + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 # full historikk for git bundle + + # ── 1. Installer rclone ─────────────────────────────────────────────── + - name: Install rclone + run: | + curl https://rclone.org/install.sh | sudo bash + rclone version + + # ── 2. Konfigurer rclone med GDrive service account ─────────────────── + # Forutsetter at RCLONE_GDRIVE_SA_JSON er lagt inn som GitHub Secret + # og at GDRIVE_BACKUP_FOLDER_ID peker på riktig GDrive-mappe + - name: Configure rclone + env: + RCLONE_GDRIVE_SA_JSON: ${{ secrets.RCLONE_GDRIVE_SA_JSON }} + GDRIVE_FOLDER_ID: ${{ secrets.GDRIVE_BACKUP_FOLDER_ID }} + run: | + mkdir -p ~/.config/rclone + cat > ~/.config/rclone/rclone.conf << EOF + [gdrive] + type = drive + scope = drive + service_account_credentials = ${RCLONE_GDRIVE_SA_JSON} + root_folder_id = ${GDRIVE_FOLDER_ID} + EOF + + # ── 3. Nøkkelfiler (MD-indeks) → GDrive/vauco-mirror/ ───────────────── + - name: Sync key docs to GDrive mirror folder + run: | + rclone copy docs/AGENT_RULEBOOK.md gdrive:vauco-mirror/ + rclone copy docs/GDRIVE_MIRROR_BOOT.md gdrive:vauco-mirror/ + rclone copy docs/LEARNINGS.md gdrive:vauco-mirror/ + rclone copy docs/VAUCO_OS_ROADMAP.md gdrive:vauco-mirror/ + rclone copy docs/TODO.md gdrive:vauco-mirror/ + rclone copy MASTERPLAN.md gdrive:vauco-mirror/ + rclone copy protocols/sessions/index.md gdrive:vauco-mirror/sessions/ + echo "[backup] Nøkkelfiler synkronisert → GDrive/vauco-mirror/" + + # ── 4. Full repo-backup som git bundle → GDrive/vauco-backup/ ───────── + - name: Create git bundle + run: | + TIMESTAMP=$(date '+%Y-%m-%dT%H%M') + BUNDLE_NAME="OSVauco-backup-${TIMESTAMP}.bundle" + git bundle create "/tmp/${BUNDLE_NAME}" --all + echo "BUNDLE_NAME=${BUNDLE_NAME}" >> $GITHUB_ENV + echo "[backup] Bundle opprettet: ${BUNDLE_NAME}" + + - name: Upload bundle to GDrive + run: | + rclone copy "/tmp/${{ env.BUNDLE_NAME }}" gdrive:vauco-backup/ + echo "[backup] Bundle lastet opp → GDrive/vauco-backup/${{ env.BUNDLE_NAME }}" + + # ── 5. Rydd gamle bundles (behold siste 7) ──────────────────────────── + - name: Prune old bundles (keep last 7) + run: | + rclone ls gdrive:vauco-backup/ \ + | sort -k2 \ + | head -n -7 \ + | awk '{print $2}' \ + | xargs -I{} rclone deletefile gdrive:vauco-backup/{} || true + echo "[backup] Gamle bundles ryddet (behold 7 siste)" + + # ── 6. Sammendrag ───────────────────────────────────────────────────── + - name: Summary + run: | + echo "=== BACKUP FERDIG ===" + echo "Tidspunkt : $(date '+%Y-%m-%dT%H:%M %Z')" + echo "Bundle : ${{ env.BUNDLE_NAME }}" + echo "Mirror : GDrive/vauco-mirror/ (nøkkelfiler)" + echo "Backup : GDrive/vauco-backup/ (git bundle)" + rclone ls gdrive:vauco-backup/ | sort -k2 | tail -7 diff --git a/docs/GDRIVE_MIRROR_BOOT.md b/docs/GDRIVE_MIRROR_BOOT.md new file mode 100644 index 0000000..fec222f --- /dev/null +++ b/docs/GDRIVE_MIRROR_BOOT.md @@ -0,0 +1,191 @@ +# VAUCO OS — GDRIVE MIRROR BOOT + +> **CONNECTOR-PRIORITET:** +> ``` +> GITHUB > GOOGLE DRIVE +> ``` +> GitHub (`OSVauco/main/docs/AGENT_RULEBOOK.md`) er **alltid** ground truth. +> Denne filen er en leseliste for agenter/tråder uten GitHub-connector (f.eks. Gemini GDrive-modus). +> Ved enhver konflikt: stol på GitHub. Oppdater denne filen etterpå. + +--- + +## ⚠️ STALENESS-VARSEL — LES DETTE FØRST + +``` +╔══════════════════════════════════════════════════════════════╗ +║ SIST SYNKRONISERT FRA GITHUB: 2026-05-25T11:18 CEST ║ +║ Kilde: OSVauco/main/docs/AGENT_RULEBOOK.md (v1.2) ║ +║ Synkronisert av: OPS-Computer-Hub ║ +╠══════════════════════════════════════════════════════════════╣ +║ ⚠️ TERSKEL: 12 TIMER (aktiv dev-runde) ║ +║ HVIS MER ENN 12T HAR GÅTT SIDEN OVENSTÅENDE TIDSPUNKT: ║ +║ → STOPP — filen er sannsynligvis utdatert. ║ +║ → Verifiser mot GitHub FØR du handler på instrukser. ║ +╠══════════════════════════════════════════════════════════════╣ +║ VERIFISER HER: ║ +║ https://github.com/chrischristiansen-glitch/OSVauco/ ║ +║ blob/main/docs/AGENT_RULEBOOK.md ║ +╠══════════════════════════════════════════════════════════════╣ +║ OPPDATER DENNE FILEN: ║ +║ 1. Åpne lenken over ║ +║ 2. Sammenlign «Sist oppdatert»-dato i AGENT_RULEBOOK.md ║ +║ 3. Hvis nyere: last ned og erstatt denne filen i GDrive ║ +╚══════════════════════════════════════════════════════════════╝ +``` + +> **Tommelfingerregel (dev-runde):** Filen er fersk i **12 timer**. Etter det — verifiser alltid. + +--- + +## CONNECTOR-GUIDE + +| Tråd/Verktøy | Connector tilgjengelig | Bruk | +|---|---|---| +| Perplexity Computer (OPS) | GitHub MCP ✅ | Les direkte fra `AGENT_RULEBOOK.md` på GitHub | +| Gemini CLI / Workstation | GDrive ✅ / GitHub ❌ | Les denne filen — verifiser staleness-varsel øverst | +| Claude (PLAN) | Varierer | Foretrekk GitHub hvis tilgjengelig, ellers GDrive | +| Nemotron / AUDIT | Varierer | Foretrekk GitHub hvis tilgjengelig, ellers GDrive | + +**Når du bruker GDrive og det har gått >12 timer siden SIST SYNKRONISERT:** +- STOPP +- Følg lenken i staleness-varselet over +- Bekreft eller oppdater før du fortsetter + +--- + +## INNHOLD — KOPI AV AGENT_RULEBOOK.md v1.2 (2026-05-21) + +> Kilde: https://github.com/chrischristiansen-glitch/OSVauco/blob/main/docs/AGENT_RULEBOOK.md + +--- + +### LOCK LIST — ALDRI ENDRE + +| Parameter | Verdi | +|---|---| +| GCP Account | chris.christiansen@vauco.no | +| Forbudte kontoer | tinius.vauger, ccv, jason.vauger | +| GCP Project | propane-will-491900-m5 (Jason-v1) | +| Billing | 0171F6-057E6B-A260BA | +| Org | vauco.no / 155051211891 | +| Region | us-central1 — ALDRI us-west1 | +| SDK | `from google import genai` — ALDRI `vertexai.generative_models` | +| Agent-rammeverk | Google ADK (tillatt) — andre krever `ADK_GODKJENT` fra Chris | +| GitHub user | chrischristiansen-glitch | +| Canonical repo | OSVauco | +| Canonical branch | main | +| MCP_NAME | OPAX-MCP | +| MCP_PROTOCOL | OPAX Protocol | +| MCP_SERVICE | opax-mcp-core (Cloud Run, us-central1) | +| ROOT_DOMAIN | vauco.no | +| HUB_URL | https://opax.vauco.no ✅ LIVE 2026-05-21 | + +--- + +### DOMENEKONVENSJON — LOCKED + +| Subdomain | Type | Formål | +|---|---|---| +| `opax.vauco.no` | Hub/MCP | OPAX-MCP operator hub — kun Vauco internt | +| `-os.vauco.no` | Prod OS | Kundens live produksjonssystem | +| `-oss.vauco.no` | Stage OS | Kundens staging/demo-system (pre-go-live) | + +> `-os` = produksjon. `-oss` = staging. Aldri omvendt. + +**Auth-strategi:** +- Nå: Google OAuth på alle miljøer +- Senere: BankID på `-os`-domener for kliniske kunder (Medioteq først) + +**Kjente/planlagte domener:** + +| Domene | Status | Cloud Run-tjeneste | +|---|---|---| +| `opax.vauco.no` | ✅ LIVE | `opax-mcp-core` | +| `medioteq-oss.vauco.no` | Planlagt | `medioteq-oss-core` | +| `medioteq-os.vauco.no` | Planlagt | `medioteq-os-core` | + +--- + +### HITL-GATES — STOPP OG SPØR ALLTID + +1. `DEPLOY GODKJENT` — før deploy til Cloud Run +2. `MERGE APPROVED` — før merge til main +3. `DEEP DREAM GODKJENT` — før strategisk vokabular eksponeres +4. `COST GODKJENT` — før endringer som påvirker billing +5. `IAM_GODKJENT` — før IAM-endringer eller ny service account +6. `NEWREPO` — før opprettelse av ny repo + +--- + +### BOOT-PROTOKOLL — kjøres av ALLE tråder ved oppstart + +1. **Connector-sjekk:** Er GitHub tilgjengelig? + - Ja → Les `docs/AGENT_RULEBOOK.md` direkte fra `OSVauco/main` + - Nei → Les denne filen (GDrive) + sjekk staleness-varsel øverst +2. Branch-discovery: list alle branches, finn mest aktiv (ahead av default) + - Hvis 1+ branch er 10+ commits ahead: STOPP og spør Chris + - Standard: `OSVauco/main` er canonical +3. Les eid fil + ROADMAP fra riktig branch +4. Bekreft i én linje: `Boot OK — branch X, HEAD Y, oppgave Z` + +--- + +### EIERSKAP-MATRISE + +| Fil | Eier | Andre kan | +|---|---|---| +| VAUCO_OS_MASTER_HANDOFF_v2.md | OPS | lese | +| VAUCO_OS_ROADMAP.md | PLAN | lese, foreslå patch via PR | +| SYSTEM_STATE_AGENT_BOOT.md | EXEC | lese | +| docs/AGENT_RULEBOOK.md | OPS | lese | +| docs/ARCHITECTURE.md | PLAN | lese, foreslå patch via PR | +| docs/LEARNINGS.md | OPS | lese, foreslå append | +| docs/RISKREGISTER.md | AUDIT | lese | +| docs/PLANBOARD.md | AUDIT | lese | +| CHANGELOG.md | OPS | lese | +| TODO.md | EXEC | lese | +| **docs/GDRIVE_MIRROR_BOOT.md** | **OPS** | lese | + +--- + +### KOST-DISIPLIN + +- $3/dag hard cap per tråd +- `gemini-2.5-flash` for enkle steg, `pro` for komplekse +- ALDRI rekursive modell-loops +- Hvis tråden bruker $1 på én oppgave: STOPP, rapporter, spør + +--- + +### VOCABULARY FIREWALL + +| Type | Ord | Regel | +|---|---|---| +| Offentlig (OK overalt) | Token Ledger, VVN, Provenance, File signature, Client identity record | Fritt bruk | +| Strategisk (KUN internt) | Pregeverdi, Deep Dream, Vauco-arv, Pregesignatur, T-konto | KUN i `deep-dream/`-mappe | + +--- + +### KORREKSJONS-REGEL + +Ground truth wins always. +1. Innrøm direkte i én setning +2. Oppdater eid fil med korreksjon +3. Fortsett +ALDRI forsvar gamle posisjoner. + +--- + +## OPPDATERINGS-LOGG (append-only) + +| Dato | Versjon | Endring | Synkronisert av | +|---|---|---|---| +| 2026-05-25 | v1.0 | Initial mirror av AGENT_RULEBOOK.md v1.2 + staleness-varsel + connector-guide | OPS-Computer-Hub | +| 2026-05-25 | v1.1 | Staleness-terskel endret fra 3 dager → 12 timer (aktiv dev-runde) | OPS-Computer-Hub | + +--- + +*Neste gang AGENT_RULEBOOK.md endres: oppdater denne filen, endre tidsstempel i staleness-varselet, og last opp til GDrive.* + +**EOF · GDRIVE_MIRROR_BOOT v1.1 · 2026-05-25 · OPS-Computer-Hub** diff --git a/docs/GDRIVE_SETUP.md b/docs/GDRIVE_SETUP.md new file mode 100644 index 0000000..8299d12 --- /dev/null +++ b/docs/GDRIVE_SETUP.md @@ -0,0 +1,114 @@ +# VAUCO OS — GDRIVE BACKUP SETUP + +> Eier: OPS-Computer-Hub · Opprettet: 2026-05-25 + +Ett-gangs oppsett for å aktivere nattlig GDrive-backup og `sync-gdrive-mirror.sh`. + +--- + +## Forutsetninger + +- GCP service account med `roles/drive.file` på GDrive-mappen +- GitHub Secrets satt (se under) +- `rclone` installert lokalt for manuell bruk + +--- + +## Steg 1 — Opprett GDrive-mapper + +Opprett to mapper i Google Drive (under `chris.christiansen@vauco.no`): + +| Mappe | Formål | +|---|---| +| `vauco-mirror/` | Nøkkelfiler (MD, indeks) — agent-lesbar | +| `vauco-backup/` | git bundle — disaster recovery | + +Kopier mappe-ID fra URL: `https://drive.google.com/drive/folders/****` + +--- + +## Steg 2 — Service account (HITL: IAM_GODKJENT) + +```bash +# Opprett service account +gcloud iam service-accounts create vauco-gdrive-backup \ + --display-name="Vauco GDrive Backup" \ + --project=propane-will-491900-m5 + +# Last ned nøkkel +gcloud iam service-accounts keys create /tmp/vauco-gdrive-sa.json \ + --iam-account=vauco-gdrive-backup@propane-will-491900-m5.iam.gserviceaccount.com +``` + +Del `vauco-backup/`- og `vauco-mirror/`-mappene med service account-e-posten: +`vauco-gdrive-backup@propane-will-491900-m5.iam.gserviceaccount.com` (Editor) + +--- + +## Steg 3 — GitHub Secrets + +Gå til: `https://github.com/chrischristiansen-glitch/OSVauco/settings/secrets/actions` + +Legg til: + +| Secret | Verdi | +|---|---| +| `RCLONE_GDRIVE_SA_JSON` | Innhold av `/tmp/vauco-gdrive-sa.json` (hele JSON-strengen) | +| `GDRIVE_BACKUP_FOLDER_ID` | Mappe-ID for `vauco-backup/` fra GDrive URL | + +--- + +## Steg 4 — Test manuelt + +```bash +# Installer rclone lokalt +curl https://rclone.org/install.sh | sudo bash + +# Konfigurer +rclone config # velg Google Drive, bruk service account JSON + +# Test sync +bash scripts/sync-gdrive-mirror.sh +``` + +--- + +## Steg 5 — Aktiver workflow + +Etter merge av PR #1: +- Workflow kjører automatisk neste natt kl 03:00 UTC +- Manuell trigger: GitHub → Actions → "Nightly GDrive Backup" → Run workflow + +--- + +## Hva som synkroniseres + +### `vauco-mirror/` (nøkkelfiler — agent-lesbar) +- `AGENT_RULEBOOK.md` +- `GDRIVE_MIRROR_BOOT.md` (auto-generert med tidsstempel) +- `LEARNINGS.md` +- `VAUCO_OS_ROADMAP.md` +- `TODO.md` +- `MASTERPLAN.md` +- `sessions/index.md` + +### `vauco-backup/` (git bundle — disaster recovery) +- `OSVauco-backup-.bundle` — full repo med all historikk +- Beholder siste 7 bundles (ca. 1 uke) + +--- + +## Gjenoppretting fra bundle + +```bash +# Last ned bundle fra GDrive +# Klon fra bundle +git clone OSVauco-backup-2026-05-25T0300.bundle OSVauco-restored +cd OSVauco-restored +git remote set-url origin https://github.com/chrischristiansen-glitch/OSVauco.git +git push --mirror origin # MERGE APPROVED kreves +``` + +--- + +**EOF · GDRIVE_SETUP v1.0 · 2026-05-25 · OPS-Computer-Hub** diff --git a/docs/TODO.md b/docs/TODO.md index 3fcf169..2ae28a4 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -1,7 +1,7 @@ # OSVauco / OPAX – TODO > Managed by PLAN thread. Update when phases move between sections. -> Last updated: 2026-05-22 +> Last updated: 2026-05-25 --- @@ -10,6 +10,16 @@ - [ ] **Phase 4** — Docs hardening: oppdater `LEARNINGS.md`, `SECRETS-SETUP.md`, `IAP-SETUP.md` med nåværende state. - [ ] Verifiser at `source scripts/osvauco-opax-boot.sh` printer NESTE OPPGAVE i grønt (Cloud Shell). - [ ] Legg til `## SLUTTRAPPORT – Phase 3` + `## NESTE OPPGAVE` blokk i `docs/OSVAUCO_OPAX_SESSION_LOG.md`. +- [ ] **GDrive backup — IAM-oppsett** (HITL: `IAM_GODKJENT` gitt 2026-05-25) + - Opprett service account: `vauco-gdrive-backup@propane-will-491900-m5.iam.gserviceaccount.com` + - Last ned JSON-nøkkel + - Del GDrive-mapper `vauco-mirror/` + `vauco-backup/` med service account (Editor) + - Se: `docs/GDRIVE_SETUP.md` for copy-paste-sekvens +- [ ] **GDrive backup — GitHub Secrets** (krever IAM-steget over) + - `RCLONE_GDRIVE_SA_JSON` — innhold av service account JSON + - `GDRIVE_BACKUP_FOLDER_ID` — mappe-ID for `vauco-backup/` fra GDrive URL + - Legg inn på: https://github.com/chrischristiansen-glitch/OSVauco/settings/secrets/actions +- [ ] **Første `mirror-sync`** — kjør etter merge for å opprette `.gdrive-mirror-state` og aktivere dashboard-status --- @@ -19,6 +29,10 @@ - [ ] `opax-mcp/` restruktureres som ordentlig modul-subtree. - [ ] Full boot cycle acceptance test (automatisert). - [ ] VS Code ↔ Cloud Shell workflow — preflight-script for lokal utvikling. +- [ ] **Gemini TUI-output logging** — `script -a`-wrapper for `gemini` + - Alias `gemini-log` starter gemini inne i terminal-recorder + - `opax-logg-slutt` appender siste 50 linjer (stripped escape-koder) til session-log + - Gjør Gemini-dialog søkbar i `OSVAUCO_OPAX_SESSION_LOG.md` --- @@ -29,6 +43,7 @@ - [ ] Multi-klient onboard-mønster (`-oss-core` → `-os-core`). - [ ] OPS agent + BigQuery live logging. - [ ] Green OSVauco-prompt med ANSI glow. +- [ ] Nattlig GDrive-backup aktiveres etter IAM + Secrets er satt opp. --- @@ -44,3 +59,4 @@ - [x] **Phase 1** — `MCP_NAME`, `MCP_PROTOCOL`, `ROOT_DOMAIN` locked; domenekonvensjon + klientmodell i `ARCHITECTURE.md`; `VAUCO_OS_ROADMAP.md` opprettet. - [x] **Phase 2** — `opax.vauco.no` LIVE: Cloud Run domain mapping + CNAME + SSL cert. `HUB_URL` locked. Boot-script peker på prod. - [x] **Phase 3** — Nemotron session loop i `.gemini/GEMINI.md`. `docs/TODO.md` opprettet. Phase 1+2 SLUTTRAPPORT i session log. +- [x] **GDrive/GitHub paritet** — `GDRIVE_MIRROR_BOOT.md` + `sync-gdrive-mirror.sh` + nattlig backup-workflow + PROMPT_COMMAND terminal-logging (2026-05-25). diff --git a/scripts/opax-logg-slutt.sh b/scripts/opax-logg-slutt.sh new file mode 100644 index 0000000..e18c577 --- /dev/null +++ b/scripts/opax-logg-slutt.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# opax-logg-slutt.sh +# Standalone sluttlogg — fungerer selv om boot.sh ikke er sourcet. +# Bruk: bash ~/OSVauco/scripts/opax-logg-slutt.sh +# Eller legg alias i ~/.bashrc: +# alias opax-logg-slutt='bash ~/OSVauco/scripts/opax-logg-slutt.sh' + +set -euo pipefail + +OSVAUCO_DIR="${OSVAUCO_DIR:-$HOME/OSVauco}" +SESSION_LOG="$OSVAUCO_DIR/docs/OSVAUCO_OPAX_SESSION_LOG.md" + +GREEN="$(tput setaf 2 2>/dev/null || echo '')" +YELLOW="$(tput setaf 3 2>/dev/null || echo '')" +NC="$(tput sgr0 2>/dev/null || echo '')" + +if [[ ! -f "$SESSION_LOG" ]]; then + echo "[WARN] Session-logg ikke funnet: $SESSION_LOG" + echo " Kjør boot først: source ~/OSVauco/scripts/osvauco-opax-boot.sh" + exit 1 +fi + +printf "\n ${GREEN}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 +- Gjort : $DONE_DESC +- Uløst : $UNSOLVED +- Slutt : $(date '+%Y-%m-%d %H:%M %Z') +EOF + +printf " ${GREEN}[OK]${NC} Logg oppdatert → %s\n\n" "$SESSION_LOG" diff --git a/scripts/osvauco-opax-boot.sh b/scripts/osvauco-opax-boot.sh old mode 100755 new mode 100644 index ddc39ae..9e3d68f --- a/scripts/osvauco-opax-boot.sh +++ b/scripts/osvauco-opax-boot.sh @@ -1,14 +1,17 @@ #!/usr/bin/env bash # ============================================================================= # osvauco-opax-boot.sh — OSVauco OPAX session-starter -# Manuell bruk: bash ~/OSVauco/scripts/osvauco-opax-boot.sh -# IKKE i ~/.bashrc — det er boot.sh sin jobb +# 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)" @@ -25,14 +28,80 @@ FAIL="${RED}[XX]${NC}" SESSION_ID="$(date '+%Y%m%d-%H%M%S')" # ============================================================================= -# Load nvm so node/npm/gemini are on PATH even when script runs as subshell +# 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='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' + +# ============================================================================= +# PROMPT_COMMAND — logger hver terminal-kommando med tidsstempel til session-log +# Aktiv så lenge dette shellet lever (ikke persistent — starter på nytt ved ny session) +# ============================================================================= +export OSVAUCO_SESSION_LOG="$SESSION_LOG" +export OSVAUCO_SESSION_ID="$SESSION_ID" + +_opax_last_cmd='' + +# trap DEBUG fanger kommandoen FØR den kjøres +trap '_opax_last_cmd=$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//")' DEBUG + +# PROMPT_COMMAND kjøres etter hver kommando (ved neste prompt) +_opax_log_cmd() { + local exit_code=$? + local cmd="$_opax_last_cmd" + # Filtrer ut interne/støy-kommandoer + [[ -z "$cmd" ]] && return + [[ "$cmd" == _opax_* ]] && return + [[ "$cmd" == "trap "* ]] && return + + local ts + ts=$(date '+%H:%M:%S') + local status_marker + if [[ $exit_code -eq 0 ]]; then + status_marker="✔" + else + status_marker="✘[$exit_code]" + fi + + # Append til session-log (stille) + printf ' %s %s %s\n' "$ts" "$status_marker" "$cmd" >> "${OSVAUCO_SESSION_LOG}" 2>/dev/null || true + _opax_last_cmd='' +} + +# Legg til i PROMPT_COMMAND (idempotent) +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" -# shellcheck source=/dev/null [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" -# Also check common system paths for gemini (e.g. symlinked to /usr/local/bin) if ! command -v gemini &>/dev/null && [[ -d "$NVM_DIR" ]]; then - # nvm may not auto-select a version in non-interactive shells NVM_DEFAULT=$(nvm version default 2>/dev/null || true) [[ -n "$NVM_DEFAULT" ]] && nvm use "$NVM_DEFAULT" &>/dev/null || true fi @@ -56,7 +125,6 @@ printf " ----------------------------------------------------\n\n" # ============================================================================= printf "${BOLD}${CYAN} [ AUTH ]${NC}\n" -# .env 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" @@ -64,7 +132,6 @@ else printf " $FAIL .env MISSING ${YELLOW}cp .env.example .env${NC}\n" fi -# gcloud 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" @@ -72,14 +139,12 @@ else printf " $FAIL gcloud ${YELLOW}gcloud auth login --no-launch-browser${NC}\n" fi -# ADC 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 -# GitHub CLI 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" @@ -87,14 +152,21 @@ else printf " $WARN GitHub CLI ${YELLOW}gh auth login (valgfritt)${NC}\n" fi -# Gemini CLI 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}Ikke installert — kjør: npm install -g @google/gemini-cli${NC}\n" + 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" @@ -112,24 +184,68 @@ printf "\n" # ============================================================================= -# SECTION 3: NESTE OPPGAVE (fra ROADMAP + TODO) +# 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" -# Hent første ugjorte oppgave under ## NEXT fra ROADMAP 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" - else - printf " ${DIM}(ingen åpne punkt under ## NEXT i ROADMAP)${NC}\n" fi -else - printf " ${WARN} ROADMAP ikke funnet: %s\n" "$ROADMAP" fi -# Hent åpne punkter fra TODO.md (maks 3) if [[ -f "$TODO" ]]; then TODO_ITEMS=$(grep -m3 '^- \[ \]' "$TODO" 2>/dev/null || true) if [[ -n "$TODO_ITEMS" ]]; then @@ -139,12 +255,11 @@ if [[ -f "$TODO" ]]; then done <<< "$TODO_ITEMS" fi fi - printf "\n" # ============================================================================= -# SECTION 4: SESSION-LOGG +# SECTION 5: SESSION-LOGG START # ============================================================================= mkdir -p "$(dirname "$SESSION_LOG")" @@ -161,10 +276,15 @@ cat >> "$SESSION_LOG" << EOF - Tid : $(date '+%Y-%m-%d %H:%M %Z') - Bruker : ${ACCOUNT:-ukjent} - OPAX : $(curl -fsS --max-time 3 "https://opax.vauco.no/ping" >/dev/null 2>&1 && echo OK || echo NEDE) +- 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\n" +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" # ============================================================================= @@ -172,27 +292,34 @@ printf " $OK Logg startet ${DIM}→ docs/OSVAUCO_OPAX_SESSION_LOG.md${NC}\ # ============================================================================= 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-HOOK +# AVSLUTT-FUNKSJON # ============================================================================= opax-logg-slutt() { + # Deaktiver PROMPT_COMMAND-logging for denne sesjonen + 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') @@ -200,7 +327,8 @@ EOF printf " ${GREEN}[OK]${NC} Logg oppdatert → docs/OSVAUCO_OPAX_SESSION_LOG.md\n\n" } export -f opax-logg-slutt 2>/dev/null || true -printf " ${DIM}Når du er ferdig → skriv: ${NC}${BOLD}opax-logg-slutt${NC}\n\n" + +printf " ${DIM}Avslutt session → ${NC}${BOLD}opax-logg-slutt${NC}\n\n" # ============================================================================= @@ -212,12 +340,6 @@ case "$ANSWER" in echo if ! command -v gemini &>/dev/null; then printf " ${RED}[XX]${NC} gemini ikke funnet.\n" - printf " Installer med:\n" - printf " curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash\n" - printf " export NVM_DIR=\"\$HOME/.nvm\" && source \"\$NVM_DIR/nvm.sh\"\n" - printf " nvm install --lts\n" - printf " npm install -g @google/gemini-cli\n" - printf " ln -sf \$(which gemini) /usr/local/bin/gemini\n" else echo " [OSVauco] Starter Gemini-CLI fra ~/OSVauco..." cd "$OSVAUCO_DIR" diff --git a/scripts/sync-gdrive-mirror.sh b/scripts/sync-gdrive-mirror.sh new file mode 100644 index 0000000..7ec3d88 --- /dev/null +++ b/scripts/sync-gdrive-mirror.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# sync-gdrive-mirror.sh +# Oppdaterer docs/GDRIVE_MIRROR_BOOT.md med fersk indeks + tidsstempel. +# Skriver .gdrive-mirror-state for å vise status i boot-dashboard. +# Kjøres manuelt: bash scripts/sync-gdrive-mirror.sh + +set -euo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" +OUTPUT="$REPO_ROOT/docs/GDRIVE_MIRROR_BOOT.md" +STATE_FILE="$REPO_ROOT/.gdrive-mirror-state" +TIMESTAMP=$(date '+%Y-%m-%dT%H:%M %Z') +SHA=$(git rev-parse --short HEAD) + +echo "[sync-gdrive-mirror] Tidsstempel: $TIMESTAMP · HEAD: $SHA" + +# ── Bygg header + staleness-varsel ───────────────────────────────────────── +cat > "$OUTPUT" << HEADER +# VAUCO OS — GDRIVE MIRROR BOOT + +> **CONNECTOR-PRIORITET:** +> \`\`\` +> GITHUB > GOOGLE DRIVE +> \`\`\` +> GitHub (\`OSVauco/main/docs/AGENT_RULEBOOK.md\`) er **alltid** ground truth. +> Denne filen er auto-generert av \`sync-gdrive-mirror.sh\`. +> Ved enhver konflikt: stol på GitHub. Oppdater ved å kjøre scriptet på nytt. + +--- + +## ⚠️ STALENESS-VARSEL — LES DETTE FØRST + +\`\`\` +╔══════════════════════════════════════════════════════════════╗ +║ SIST SYNKRONISERT: $TIMESTAMP ║ +║ HEAD: $SHA ║ +║ Kilde: OSVauco/main · Synkronisert av: sync-gdrive-mirror.sh ║ +╠══════════════════════════════════════════════════════════════╣ +║ ⚠️ TERSKEL: 12 TIMER (aktiv dev-runde) ║ +║ HVIS MER ENN 12T HAR GÅTT: STOPP og verifiser mot GitHub ║ +╠══════════════════════════════════════════════════════════════╣ +║ VERIFISER: https://github.com/chrischristiansen-glitch/ ║ +║ OSVauco/blob/main/docs/AGENT_RULEBOOK.md ║ +╚══════════════════════════════════════════════════════════════╝ +\`\`\` + +--- + +## PROSJEKTINDEKS — AUTO-GENERERT $TIMESTAMP · HEAD $SHA + +HEADER + +# ── Legg inn TODO ────────────────────────────────────────────────────────── +if [[ -f "$REPO_ROOT/docs/TODO.md" ]]; then + echo -e "\n---\n\n## TODO\n" >> "$OUTPUT" + cat "$REPO_ROOT/docs/TODO.md" >> "$OUTPUT" +fi + +if [[ -f "$REPO_ROOT/protocols/sessions/index.md" ]]; then + echo -e "\n---\n\n## SESJONSLOGG\n" >> "$OUTPUT" + cat "$REPO_ROOT/protocols/sessions/index.md" >> "$OUTPUT" +fi + +if [[ -f "$REPO_ROOT/docs/VAUCO_OS_ROADMAP.md" ]]; then + echo -e "\n---\n\n## ROADMAP\n" >> "$OUTPUT" + cat "$REPO_ROOT/docs/VAUCO_OS_ROADMAP.md" >> "$OUTPUT" +fi + +if [[ -f "$REPO_ROOT/docs/AGENT_RULEBOOK.md" ]]; then + echo -e "\n---\n\n## AGENT_RULEBOOK\n" >> "$OUTPUT" + cat "$REPO_ROOT/docs/AGENT_RULEBOOK.md" >> "$OUTPUT" +fi + +if [[ -f "$REPO_ROOT/docs/LEARNINGS.md" ]]; then + echo -e "\n---\n\n## LEARNINGS — siste oppføringer\n" >> "$OUTPUT" + tail -60 "$REPO_ROOT/docs/LEARNINGS.md" >> "$OUTPUT" +fi + +# ── Footer ──────────────────────────────────────────────────────────────── +cat >> "$OUTPUT" << FOOTER + +--- + +*Oppdater ved å kjøre: \`bash scripts/sync-gdrive-mirror.sh\` — last deretter opp til GDrive.* + +**EOF · GDRIVE_MIRROR_BOOT · $TIMESTAMP · HEAD $SHA · auto-generert** +FOOTER + +# ── Skriv state-fil (for boot-dashboard) ─────────────────────────────── +cat > "$STATE_FILE" << STATE +LAST_SYNC=$TIMESTAMP +LAST_SHA=$SHA +STATE + +# ── Commit + push ───────────────────────────────────────────────────────── +cd "$REPO_ROOT" +git add docs/GDRIVE_MIRROR_BOOT.md .gdrive-mirror-state +git commit -m "chore(docs): sync GDRIVE_MIRROR_BOOT $TIMESTAMP [HEAD $SHA]" +git push origin main + +echo "[sync-gdrive-mirror] Ferdig. Last ned docs/GDRIVE_MIRROR_BOOT.md og erstatt i GDrive."