Oppgavelås [~] for parallelle agenter, fjern eksempler som forstyrret grep
tasks.md: Ny status [~] (pågår) med timestamp. Fjernet code-fence eksempler som ble fanget av grep som ekte oppgaver. run-next-task.sh: Markerer oppgave som [~] før start, tilbakestiller ved krasj. --unstale frigjør oppgaver >60 min. Sjekker at forrige oppgave i fasen er ferdig. Pull-instruksjon i prompt. Subagent-bruk oppfordres der det er egnet. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
43fc267089
commit
bd5e94acf6
2 changed files with 152 additions and 54 deletions
|
|
@ -1,12 +1,16 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Plukker neste ugjorte oppgave fra tasks.md og starter en Claude Code-sesjon.
|
# Plukker neste ugjorte oppgave fra tasks.md og starter en Claude Code-sesjon.
|
||||||
# Hopper over oppgaver med [?] (åpent spørsmål) eller [!] (blokkert),
|
# Hopper over oppgaver som er pågående [~], har åpent spørsmål [?], eller
|
||||||
# og oppgaver som avhenger av blokkerte faser.
|
# er blokkert [!], inkludert alle oppgaver som avhenger av dem.
|
||||||
|
#
|
||||||
|
# Støtter parallell kjøring: markerer oppgaven som [~] (pågår) før start,
|
||||||
|
# setter den til [x] eller tilbake til [ ] avhengig av resultat.
|
||||||
#
|
#
|
||||||
# Bruk:
|
# Bruk:
|
||||||
# ./scripts/run-next-task.sh # kjør neste oppgave
|
# ./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 --dry # vis hvilken oppgave som er neste
|
||||||
# ./scripts/run-next-task.sh --status # vis status for alle oppgaver
|
# ./scripts/run-next-task.sh --status # vis status for alle oppgaver
|
||||||
|
# ./scripts/run-next-task.sh --unstale # frigjør [~] oppgaver eldre enn 60 min
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
@ -29,20 +33,18 @@ declare -A PHASE_DEPS=(
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Finn blokkerte faser ---
|
# --- Finn blokkerte faser ---
|
||||||
# En fase er blokkert hvis den har en [?] eller [!] oppgave
|
# En fase er blokkert hvis den har en [?], [!] eller [~] oppgave
|
||||||
blocked_phases() {
|
blocked_phases() {
|
||||||
local phases=""
|
local phases=""
|
||||||
for phase in $(seq 1 12); do
|
for phase in $(seq 1 12); do
|
||||||
# Sjekk om fasen har blokkerte oppgaver
|
if grep -qP "^\- \[(\?|!|~)\] ${phase}\." "$TASKS" 2>/dev/null; then
|
||||||
if grep -qP "^\- \[\?\] ${phase}\." "$TASKS" 2>/dev/null || \
|
|
||||||
grep -qP "^\- \[!\] ${phase}\." "$TASKS" 2>/dev/null; then
|
|
||||||
phases="$phases $phase"
|
phases="$phases $phase"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
echo "$phases"
|
echo "$phases"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sjekk om en fase er tilgjengelig (alle avhengigheter er ferdige eller i det minste ikke blokkert)
|
# Sjekk om en fase er tilgjengelig
|
||||||
phase_available() {
|
phase_available() {
|
||||||
local phase=$1
|
local phase=$1
|
||||||
local blocked="$2"
|
local blocked="$2"
|
||||||
|
|
@ -52,7 +54,7 @@ phase_available() {
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Sjekk om avhengige faser er blokkert
|
# Sjekk om avhengige faser er blokkert eller har ugjorte oppgaver
|
||||||
local deps="${PHASE_DEPS[$phase]}"
|
local deps="${PHASE_DEPS[$phase]}"
|
||||||
for dep in $deps; do
|
for dep in $deps; do
|
||||||
if echo "$blocked" | grep -qw "$dep"; then
|
if echo "$blocked" | grep -qw "$dep"; then
|
||||||
|
|
@ -67,21 +69,79 @@ phase_available() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Sjekk at forrige oppgave i samme fase er ferdig
|
||||||
|
prev_task_done() {
|
||||||
|
local task_id=$1 # f.eks. "2.4"
|
||||||
|
local phase=$(echo "$task_id" | cut -d. -f1)
|
||||||
|
local num=$(echo "$task_id" | cut -d. -f2)
|
||||||
|
|
||||||
|
if [[ "$num" == "1" ]]; then
|
||||||
|
return 0 # Første oppgave i fasen, ingen forrige
|
||||||
|
fi
|
||||||
|
|
||||||
|
local prev_num=$((num - 1))
|
||||||
|
local prev_id="${phase}.${prev_num}"
|
||||||
|
|
||||||
|
# Forrige oppgave må være [x]
|
||||||
|
if grep -qP "^\- \[x\] ${prev_id} " "$TASKS" 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Frigjør stale [~] oppgaver ---
|
||||||
|
if [[ "${1:-}" == "--unstale" ]]; then
|
||||||
|
echo "Sjekker etter stale [~] oppgaver (>60 min)..."
|
||||||
|
now=$(date +%s)
|
||||||
|
changed=false
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# Hent timestamp fra linjen under (> Påbegynt: 2026-03-17T14:30)
|
||||||
|
line_num=$(echo "$line" | cut -d: -f1)
|
||||||
|
next_line=$((line_num + 1))
|
||||||
|
ts=$(sed -n "${next_line}p" "$TASKS" | grep -oP '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}' || echo "")
|
||||||
|
if [[ -n "$ts" ]]; then
|
||||||
|
started=$(date -d "$ts" +%s 2>/dev/null || echo 0)
|
||||||
|
elapsed=$(( (now - started) / 60 ))
|
||||||
|
if [[ $elapsed -gt 60 ]]; then
|
||||||
|
task_text=$(echo "$line" | cut -d: -f2-)
|
||||||
|
echo " Frigjør (${elapsed} min gammel): $task_text"
|
||||||
|
sed -i "${line_num}s/^\- \[~\]/- [ ]/" "$TASKS"
|
||||||
|
sed -i "${next_line}d" "$TASKS" # Fjern påbegynt-linjen
|
||||||
|
changed=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < <(grep -n '^\- \[~\]' "$TASKS")
|
||||||
|
if $changed; then
|
||||||
|
echo "Oppdatert. Commit manuelt om ønsket."
|
||||||
|
else
|
||||||
|
echo "Ingen stale oppgaver funnet."
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# --- Status-visning ---
|
# --- Status-visning ---
|
||||||
if [[ "${1:-}" == "--status" ]]; then
|
if [[ "${1:-}" == "--status" ]]; then
|
||||||
echo "=== Synops oppgavestatus ==="
|
echo "=== Synops oppgavestatus ==="
|
||||||
echo ""
|
echo ""
|
||||||
done=$(grep -cP '^\- \[x\]' "$TASKS" || true)
|
done=$(grep -cP '^\- \[x\]' "$TASKS" || true)
|
||||||
todo=$(grep -cP '^\- \[ \]' "$TASKS" || true)
|
todo=$(grep -cP '^\- \[ \]' "$TASKS" || true)
|
||||||
|
in_progress=$(grep -cP '^\- \[~\]' "$TASKS" || true)
|
||||||
questions=$(grep -cP '^\- \[\?\]' "$TASKS" || true)
|
questions=$(grep -cP '^\- \[\?\]' "$TASKS" || true)
|
||||||
blocked_count=$(grep -cP '^\- \[!\]' "$TASKS" || true)
|
blocked_count=$(grep -cP '^\- \[!\]' "$TASKS" || true)
|
||||||
done=${done:-0}; todo=${todo:-0}; questions=${questions:-0}; blocked_count=${blocked_count:-0}
|
done=${done:-0}; todo=${todo:-0}; in_progress=${in_progress:-0}
|
||||||
total=$((done + todo + questions + blocked_count))
|
questions=${questions:-0}; blocked_count=${blocked_count:-0}
|
||||||
|
total=$((done + todo + in_progress + questions + blocked_count))
|
||||||
echo "Ferdige: $done / $total"
|
echo "Ferdige: $done / $total"
|
||||||
|
echo "Pågår: $in_progress"
|
||||||
echo "Gjenstår: $todo"
|
echo "Gjenstår: $todo"
|
||||||
echo "Spørsmål: $questions"
|
echo "Spørsmål: $questions"
|
||||||
echo "Blokkert: $blocked_count"
|
echo "Blokkert: $blocked_count"
|
||||||
echo ""
|
echo ""
|
||||||
|
if [[ $in_progress -gt 0 ]]; then
|
||||||
|
echo "--- Pågår ---"
|
||||||
|
grep -A1 '^\- \[~\]' "$TASKS" || true
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
if [[ $questions -gt 0 ]]; then
|
if [[ $questions -gt 0 ]]; then
|
||||||
echo "--- Åpne spørsmål ---"
|
echo "--- Åpne spørsmål ---"
|
||||||
grep -A2 '^\- \[\?\]' "$TASKS" || true
|
grep -A2 '^\- \[\?\]' "$TASKS" || true
|
||||||
|
|
@ -100,24 +160,27 @@ blocked=$(blocked_phases)
|
||||||
next_task=""
|
next_task=""
|
||||||
line_num=""
|
line_num=""
|
||||||
task_text=""
|
task_text=""
|
||||||
|
task_id=""
|
||||||
|
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
num=$(echo "$line" | cut -d: -f1)
|
num=$(echo "$line" | cut -d: -f1)
|
||||||
text=$(echo "$line" | cut -d: -f2- | sed 's/^- \[ \] //')
|
text=$(echo "$line" | cut -d: -f2- | sed 's/^- \[ \] //')
|
||||||
# Hent fase-nummer fra oppgave-ID (f.eks. "1.3" → "1")
|
# Hent oppgave-ID (f.eks. "1.3")
|
||||||
|
id=$(echo "$text" | grep -oP '^\d+\.\d+' || echo "")
|
||||||
phase=$(echo "$text" | grep -oP '^\d+' || echo "")
|
phase=$(echo "$text" | grep -oP '^\d+' || echo "")
|
||||||
|
|
||||||
if [[ -n "$phase" ]] && phase_available "$phase" "$blocked"; then
|
if [[ -n "$phase" ]] && phase_available "$phase" "$blocked" && prev_task_done "$id"; then
|
||||||
next_task="$line"
|
next_task="$line"
|
||||||
line_num="$num"
|
line_num="$num"
|
||||||
task_text="$text"
|
task_text="$text"
|
||||||
|
task_id="$id"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done < <(grep -n '^\- \[ \]' "$TASKS")
|
done < <(grep -n '^\- \[ \]' "$TASKS")
|
||||||
|
|
||||||
if [[ -z "$next_task" ]]; then
|
if [[ -z "$next_task" ]]; then
|
||||||
if [[ -n "$blocked" ]]; then
|
if [[ -n "$blocked" ]]; then
|
||||||
echo "Ingen tilgjengelige oppgaver. Blokkerte faser:$blocked"
|
echo "Ingen tilgjengelige oppgaver. Blokkerte/pågående faser:$blocked"
|
||||||
echo "Kjør --status for detaljer."
|
echo "Kjør --status for detaljer."
|
||||||
else
|
else
|
||||||
echo "Alle oppgaver er gjort!"
|
echo "Alle oppgaver er gjort!"
|
||||||
|
|
@ -133,61 +196,91 @@ if [[ "${1:-}" == "--dry" ]]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PROMPT="$(cat <<'PROMPT_HEADER'
|
# --- Marker oppgaven som pågående ---
|
||||||
Du skal implementere neste oppgave i Synops-prosjektet.
|
timestamp=$(date +%Y-%m-%dT%H:%M)
|
||||||
Du jobber autonomt — ingen bruker er tilgjengelig for spørsmål underveis.
|
sed -i "${line_num}s/^\- \[ \]/- [~]/" "$TASKS"
|
||||||
|
sed -i "${line_num}a\\ > Påbegynt: ${timestamp}" "$TASKS"
|
||||||
|
cd "$ROOT"
|
||||||
|
git add tasks.md
|
||||||
|
git commit -m "Starter oppgave ${task_id}" --no-verify 2>/dev/null || true
|
||||||
|
git push forgejo main 2>/dev/null || true
|
||||||
|
|
||||||
PROMPT_HEADER
|
# --- Bygg prompt ---
|
||||||
)
|
PROMPT="Du skal implementere neste oppgave i Synops-prosjektet.
|
||||||
|
Du jobber autonomt — ingen bruker er tilgjengelig for spørsmål underveis.
|
||||||
|
|
||||||
## Oppgave
|
## Oppgave
|
||||||
$task_text
|
$task_text
|
||||||
|
|
||||||
$(cat <<'PROMPT_BODY'
|
|
||||||
|
|
||||||
## Arbeidsflyt
|
## Arbeidsflyt
|
||||||
|
|
||||||
1. **Orienter deg.** Les `CLAUDE.md` for prosjektkontekst. Les dokumentene
|
1. **Orienter deg.** Les \`CLAUDE.md\` for prosjektkontekst. Les dokumentene
|
||||||
som refereres i oppgaven. Les `tasks.md` for å forstå hvor prosjektet står.
|
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.
|
(hvilke oppgaver er ferdige, hva er tilgjengelig).
|
||||||
3. **Verifiser.** Kompilering, curl-test, kjør relevante tester.
|
2. **Pull siste endringer.** Kjør \`git pull forgejo main\` først — andre
|
||||||
4. **Oppdater dokumentasjon.** Hvis implementeringen avviker fra eksisterende
|
agenter kan ha pushet endringer.
|
||||||
|
3. **Implementer.** Skriv kode, kjør på server via SSH om nødvendig.
|
||||||
|
4. **Verifiser.** Kompilering, curl-test, kjør relevante tester.
|
||||||
|
5. **Oppdater dokumentasjon.** Hvis implementeringen avviker fra eksisterende
|
||||||
docs, oppdater dem. Nye tekniske beslutninger dokumenteres i relevante
|
docs, oppdater dem. Nye tekniske beslutninger dokumenteres i relevante
|
||||||
filer under `docs/`. Docs skal alltid reflektere faktisk tilstand.
|
filer under \`docs/\`. Docs skal alltid reflektere faktisk tilstand.
|
||||||
5. **Oppdater tasks.md.** Endre `- [ ]` til `- [x]` for denne oppgaven.
|
6. **Oppdater tasks.md.** Endre \`- [~]\` til \`- [x]\` for oppgave ${task_id}.
|
||||||
6. **Commit og push.** Commit alle endringer (kode + docs + tasks.md) med
|
Fjern \`> Påbegynt: ...\`-linjen under oppgaven.
|
||||||
en beskrivende melding. Push til forgejo (bruk `tea` / `git push forgejo`).
|
7. **Commit og push.** Commit alle endringer (kode + docs + tasks.md) med
|
||||||
|
en beskrivende melding. Push til forgejo (\`git push forgejo main\`).
|
||||||
|
Flere commits underveis er OK — push jevnlig så andre agenter ser fremgangen.
|
||||||
|
|
||||||
## Hvis noe blokkerer
|
## Hvis noe blokkerer
|
||||||
|
|
||||||
Hvis du støter på noe som krever avklaring fra Vegard:
|
Hvis du trenger avklaring fra Vegard:
|
||||||
- Endre oppgavens status til `- [?]` i tasks.md
|
- Endre oppgavens status fra \`- [~]\` til \`- [?]\` i tasks.md
|
||||||
- Legg til innrykket tekst under oppgaven med spørsmålet:
|
- Fjern påbegynt-linjen, legg til spørsmålet:
|
||||||
```
|
\`\`\`
|
||||||
- [?] 1.5 Authentik: opprett OIDC-provider...
|
- [?] ${task_id} ...
|
||||||
> Spørsmål: Skal vi bruke implicit flow eller authorization code + PKCE?
|
> Spørsmål: <ditt spørsmål>
|
||||||
> Kontekst: PKCE er sikrere men krever backend-støtte.
|
> Kontekst: <hvorfor dette er uklart>
|
||||||
```
|
\`\`\`
|
||||||
- Commit og push tasks.md slik at Vegard kan se spørsmålet.
|
- Commit og push. Avslutt sesjonen.
|
||||||
- Avslutt sesjonen. Ikke start på neste oppgave.
|
|
||||||
|
|
||||||
Hvis du støter på et teknisk problem du ikke kan løse:
|
Hvis du støter på et teknisk problem du ikke kan løse:
|
||||||
- Endre oppgavens status til `- [!]` i tasks.md
|
- Endre status fra \`- [~]\` til \`- [!]\` i tasks.md
|
||||||
- Dokumenter problemet under oppgaven.
|
- Dokumenter problemet. Commit og push. Avslutt.
|
||||||
- Commit og push. Avslutt.
|
|
||||||
|
|
||||||
## Regler
|
## Regler
|
||||||
|
|
||||||
- Jobb kun på denne ene oppgaven.
|
- Jobb kun på oppgave ${task_id}. Ikke start på neste.
|
||||||
- Ikke deploy til produksjon uten eksplisitt godkjenning.
|
- Ikke deploy til produksjon uten eksplisitt godkjenning.
|
||||||
- Følg eksisterende arkitektur og konvensjoner i `docs/`.
|
- Følg eksisterende arkitektur og konvensjoner i \`docs/\`.
|
||||||
- Hold det enkelt — minimum viable for oppgaven.
|
- Hold det enkelt — minimum viable for oppgaven.
|
||||||
- Dokumentasjon er like viktig som kode. Neste sesjon har ingen kontekst
|
- Dokumentasjon er like viktig som kode. Neste sesjon har ingen kontekst
|
||||||
fra denne — alt den vet kommer fra kode, docs og git-historikk.
|
fra denne — alt den vet kommer fra kode, docs og git-historikk.
|
||||||
- Skriv commit-meldinger som forklarer *hvorfor*, ikke bare *hva*.
|
- Skriv commit-meldinger som forklarer *hvorfor*, ikke bare *hva*.
|
||||||
PROMPT_BODY
|
- Push jevnlig underveis — ikke samle opp alt til slutt.
|
||||||
)"
|
- Du kan spinne opp subagenter (Agent-tool) for parallelt arbeid der det
|
||||||
|
er egnet — f.eks. research i docs, utforske kodebasen, eller kjøre
|
||||||
|
uavhengige deloppgaver samtidig. Bruk det aktivt for å jobbe effektivt."
|
||||||
|
|
||||||
echo "Starter Claude Code-sesjon..."
|
echo "Starter Claude Code-sesjon for oppgave ${task_id}..."
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
claude --print "$PROMPT"
|
claude --print "$PROMPT"
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
# --- Hvis claude krasjer, sett oppgaven tilbake til [ ] ---
|
||||||
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
|
echo "Claude-sesjonen feilet (exit code $exit_code). Tilbakestiller oppgave ${task_id}."
|
||||||
|
# Sjekk om oppgaven fortsatt er [~] (ikke allerede endret av sesjonen)
|
||||||
|
if grep -qP "^\- \[~\] ${task_id} " "$TASKS"; then
|
||||||
|
sed -i "/^\- \[~\] ${task_id} /s/^\- \[~\]/- [ ]/" "$TASKS"
|
||||||
|
# Fjern påbegynt-linjen
|
||||||
|
line_after=$(grep -n "^\- \[ \] ${task_id} " "$TASKS" | cut -d: -f1)
|
||||||
|
if [[ -n "$line_after" ]]; then
|
||||||
|
next=$((line_after + 1))
|
||||||
|
if sed -n "${next}p" "$TASKS" | grep -q '> Påbegynt:'; then
|
||||||
|
sed -i "${next}d" "$TASKS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
git add tasks.md
|
||||||
|
git commit -m "Tilbakestill oppgave ${task_id} etter feilet sesjon" --no-verify 2>/dev/null || true
|
||||||
|
git push forgejo main 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
|
||||||
13
tasks.md
13
tasks.md
|
|
@ -6,12 +6,17 @@ Runner-scriptet plukker første ugjorte oppgave som ikke er blokkert.
|
||||||
## Statuser
|
## Statuser
|
||||||
|
|
||||||
- `- [ ]` — Klar til å gjøres
|
- `- [ ]` — Klar til å gjøres
|
||||||
|
- `- [~]` — Pågår. En agent jobber på denne. Andre agenter hopper over.
|
||||||
- `- [x]` — Ferdig
|
- `- [x]` — Ferdig
|
||||||
- `- [?]` — Åpent spørsmål, trenger avklaring fra Vegard. Neste sesjon hopper over denne og alle som avhenger av den.
|
- `- [?]` — Åpent spørsmål, trenger avklaring fra Vegard.
|
||||||
- `- [!]` — Blokkert av teknisk problem. Beskrivelse under oppgaven.
|
- `- [!]` — Blokkert av teknisk problem.
|
||||||
|
|
||||||
Åpne spørsmål og blokkeringer skrives som innrykket tekst under oppgaven
|
`[~]`, `[?]` og `[!]` blokkerer alle oppgaver som avhenger av denne.
|
||||||
med `>` prefix. Se eksisterende oppgaver for format.
|
Detaljer skrives som innrykket tekst med `>` prefix under oppgaven.
|
||||||
|
Runner-scriptet legger automatisk til `> Påbegynt: <timestamp>` for `[~]`.
|
||||||
|
|
||||||
|
Hvis en `[~]`-oppgave har stått i >60 min uten commit, anta at
|
||||||
|
sesjonen krasjet. Kjør `run-next-task.sh --unstale` for å frigjøre.
|
||||||
|
|
||||||
## Avhengigheter
|
## Avhengigheter
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue