synops/scripts/run-next-task.sh
vegard 43fc267089 Legg til task-liste og autonom runner for implementering
tasks.md: 51 oppgaver i 12 faser med avhengighetskart og
statusmarkører ([?] for åpne spørsmål, [!] for blokkert).

run-next-task.sh: plukker neste tilgjengelige oppgave, hopper
over blokkerte faser og deres avhengigheter, starter fersk
Claude Code-sesjon med full kontekst-prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 11:35:22 +01:00

193 lines
5.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Plukker neste ugjorte oppgave fra tasks.md og starter en Claude Code-sesjon.
# Hopper over oppgaver med [?] (åpent spørsmål) eller [!] (blokkert),
# og oppgaver som avhenger av blokkerte faser.
#
# Bruk:
# ./scripts/run-next-task.sh # kjør neste oppgave
# ./scripts/run-next-task.sh --dry # vis hvilken oppgave som er neste
# ./scripts/run-next-task.sh --status # vis status for alle oppgaver
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
TASKS="$ROOT/tasks.md"
# --- Avhengighetskart: fase → faser den avhenger av ---
declare -A PHASE_DEPS=(
[1]=""
[2]="1"
[3]="2"
[4]="2"
[5]="3 4"
[6]="2"
[7]="6"
[8]="5"
[9]="3"
[10]="2"
[11]="5 6 7"
[12]="1 2 3 4 5 6 7 8 9 10 11"
)
# --- Finn blokkerte faser ---
# En fase er blokkert hvis den har en [?] eller [!] oppgave
blocked_phases() {
local phases=""
for phase in $(seq 1 12); do
# Sjekk om fasen har blokkerte oppgaver
if grep -qP "^\- \[\?\] ${phase}\." "$TASKS" 2>/dev/null || \
grep -qP "^\- \[!\] ${phase}\." "$TASKS" 2>/dev/null; then
phases="$phases $phase"
fi
done
echo "$phases"
}
# Sjekk om en fase er tilgjengelig (alle avhengigheter er ferdige eller i det minste ikke blokkert)
phase_available() {
local phase=$1
local blocked="$2"
# Sjekk om denne fasen selv er blokkert
if echo "$blocked" | grep -qw "$phase"; then
return 1
fi
# Sjekk om avhengige faser er blokkert
local deps="${PHASE_DEPS[$phase]}"
for dep in $deps; do
if echo "$blocked" | grep -qw "$dep"; then
return 1
fi
# Sjekk at alle oppgaver i avhengig fase er ferdige
if grep -qP "^\- \[ \] ${dep}\." "$TASKS" 2>/dev/null; then
return 1
fi
done
return 0
}
# --- Status-visning ---
if [[ "${1:-}" == "--status" ]]; then
echo "=== Synops oppgavestatus ==="
echo ""
done=$(grep -cP '^\- \[x\]' "$TASKS" || true)
todo=$(grep -cP '^\- \[ \]' "$TASKS" || true)
questions=$(grep -cP '^\- \[\?\]' "$TASKS" || true)
blocked_count=$(grep -cP '^\- \[!\]' "$TASKS" || true)
done=${done:-0}; todo=${todo:-0}; questions=${questions:-0}; blocked_count=${blocked_count:-0}
total=$((done + todo + questions + blocked_count))
echo "Ferdige: $done / $total"
echo "Gjenstår: $todo"
echo "Spørsmål: $questions"
echo "Blokkert: $blocked_count"
echo ""
if [[ $questions -gt 0 ]]; then
echo "--- Åpne spørsmål ---"
grep -A2 '^\- \[\?\]' "$TASKS" || true
echo ""
fi
if [[ $blocked_count -gt 0 ]]; then
echo "--- Blokkerte oppgaver ---"
grep -A2 '^\- \[!\]' "$TASKS" || true
fi
exit 0
fi
# --- Finn neste oppgave ---
blocked=$(blocked_phases)
next_task=""
line_num=""
task_text=""
while IFS= read -r line; do
num=$(echo "$line" | cut -d: -f1)
text=$(echo "$line" | cut -d: -f2- | sed 's/^- \[ \] //')
# Hent fase-nummer fra oppgave-ID (f.eks. "1.3" → "1")
phase=$(echo "$text" | grep -oP '^\d+' || echo "")
if [[ -n "$phase" ]] && phase_available "$phase" "$blocked"; then
next_task="$line"
line_num="$num"
task_text="$text"
break
fi
done < <(grep -n '^\- \[ \]' "$TASKS")
if [[ -z "$next_task" ]]; then
if [[ -n "$blocked" ]]; then
echo "Ingen tilgjengelige oppgaver. Blokkerte faser:$blocked"
echo "Kjør --status for detaljer."
else
echo "Alle oppgaver er gjort!"
fi
exit 0
fi
echo "Neste oppgave (linje $line_num):"
echo " $task_text"
echo ""
if [[ "${1:-}" == "--dry" ]]; then
exit 0
fi
PROMPT="$(cat <<'PROMPT_HEADER'
Du skal implementere neste oppgave i Synops-prosjektet.
Du jobber autonomt — ingen bruker er tilgjengelig for spørsmål underveis.
PROMPT_HEADER
)
## Oppgave
$task_text
$(cat <<'PROMPT_BODY'
## Arbeidsflyt
1. **Orienter deg.** Les `CLAUDE.md` for prosjektkontekst. Les dokumentene
som refereres i oppgaven. Les `tasks.md` for å forstå hvor prosjektet står.
2. **Implementer.** Skriv kode, kjør på server via SSH om nødvendig.
3. **Verifiser.** Kompilering, curl-test, kjør relevante tester.
4. **Oppdater dokumentasjon.** Hvis implementeringen avviker fra eksisterende
docs, oppdater dem. Nye tekniske beslutninger dokumenteres i relevante
filer under `docs/`. Docs skal alltid reflektere faktisk tilstand.
5. **Oppdater tasks.md.** Endre `- [ ]` til `- [x]` for denne oppgaven.
6. **Commit og push.** Commit alle endringer (kode + docs + tasks.md) med
en beskrivende melding. Push til forgejo (bruk `tea` / `git push forgejo`).
## Hvis noe blokkerer
Hvis du støter på noe som krever avklaring fra Vegard:
- Endre oppgavens status til `- [?]` i tasks.md
- Legg til innrykket tekst under oppgaven med spørsmålet:
```
- [?] 1.5 Authentik: opprett OIDC-provider...
> Spørsmål: Skal vi bruke implicit flow eller authorization code + PKCE?
> Kontekst: PKCE er sikrere men krever backend-støtte.
```
- Commit og push tasks.md slik at Vegard kan se spørsmålet.
- Avslutt sesjonen. Ikke start på neste oppgave.
Hvis du støter på et teknisk problem du ikke kan løse:
- Endre oppgavens status til `- [!]` i tasks.md
- Dokumenter problemet under oppgaven.
- Commit og push. Avslutt.
## Regler
- Jobb kun på denne ene oppgaven.
- Ikke deploy til produksjon uten eksplisitt godkjenning.
- Følg eksisterende arkitektur og konvensjoner i `docs/`.
- Hold det enkelt — minimum viable for oppgaven.
- Dokumentasjon er like viktig som kode. Neste sesjon har ingen kontekst
fra denne — alt den vet kommer fra kode, docs og git-historikk.
- Skriv commit-meldinger som forklarer *hvorfor*, ikke bare *hva*.
PROMPT_BODY
)"
echo "Starter Claude Code-sesjon..."
cd "$ROOT"
claude --print "$PROMPT"