diff --git a/.claude/skills/build-marp-deck/SKILL.md b/.claude/skills/build-marp-deck/SKILL.md new file mode 100644 index 0000000..ae6ddac --- /dev/null +++ b/.claude/skills/build-marp-deck/SKILL.md @@ -0,0 +1,222 @@ +--- +name: build-marp-deck +description: Bouw of bewerk een Marp presentatie (.md → HTML/PDF) in de Npuls huisstijl, met live preview-server en visuele overflow-controle. Gebruik wanneer iemand "maak een marp", "bouw een deck", "marp presentatie", "preview", "preview venster", "live preview", "open de marp" vraagt, of /build-marp-deck aanroept. Bij een Marp-deck open je standaard de live preview-server (niet losse HTML in de browser). Voor Slidev gebruik je clidev; dit is puur Marp. +--- + +# Build Marp Deck + +Maak Marp presentaties in de CEDA/Npuls huisstijl. Marp rendert Markdown → slides via de +`marp` CLI. Deze skill bundelt het `npuls` thema en de werkende slide-patronen, en bakt een +**render → visueel checken → fixen** loop in zodat overflow niet stilletjes blijft staan. + +Marp is bewust **niet** Slidev. Wil iemand Slidev? → gebruik `clidev`. + +## Live preview (standaard tijdens bewerken) + +Zodra je een deck **bouwt of bewerkt**, start meteen de Marp preview-server in plaats van +losse HTML in de browser te openen. De server heeft **live reload**: elke save aan de `.md` +ververst het venster vanzelf — geen handmatige re-render per wijziging. + +```bash +marp --preview --server . +``` + +Start dit **in de achtergrond** (Bash `run_in_background: true`), open daarna het deck direct: + +```bash +open "http://localhost:8080/.md" +``` + +- `--server .` serveert de map (live reload); `--preview` opent het preview-venster. +- Draait er al een server op 8080? Niet opnieuw starten — alleen de deck-URL openen. +- Triggers: "preview", "preview mode", "preview venster", "live", "open de marp" → start dit, + niet de statische `deck.html` in de browser. + +Stoppen: + +```bash +pkill -f "marp --preview" +``` + +> De statische render (`marp deck.md -o exports/deck.html` + `--pdf -o exports/deck.pdf`) +> levert de **eindproducten** in de `exports/`-submap. Voor het iteratief bouwen/bekijken is +> de HTML preview-server (live reload) of de PDF-watch (stap 3b) sneller. + +## Stap 1 — Setup (altijd eerst) + +Controleer of de `marp` CLI bestaat: + +```bash +which marp || echo "niet aanwezig" +``` + +Niet aanwezig? Installeer: + +```bash +brew install marp-cli +``` + +Kopieer het thema naar de projectmap als het er nog niet staat (assets zitten in deze skill): + +```bash +SKILL_DIR="$HOME/.claude/skills/build-marp-deck/assets" +[ -f npuls.css ] || cp "$SKILL_DIR/npuls.css" . +[ -f .marprc.yml ] || cp "$SKILL_DIR/.marprc.yml" . +``` + +`.marprc.yml` (`themeSet: [npuls.css]`) zorgt dat `marp` het thema automatisch laadt — geen +`--theme` vlag nodig zolang je vanuit die map rendert. + +## Stap 2 — Schrijf de deck + +Begin elke deck met deze frontmatter: + +```yaml +--- +marp: true +theme: npuls +paginate: true +--- +``` + +- Slides scheiden met `---` op een eigen regel. +- Per-slide variant: `` bovenaan de slide (underscore = alléén deze slide). +- Gebruik `assets/_template.md` als startpunt — die toont alle slide-classes in actie. + +### Slide-classes (uit `npuls.css`) + +| Class | Effect | +|-------|--------| +| `title` | Blauwe titelslide, gecentreerd (ondertitel roze) | +| `divider` | Oranje full-bleed sectie-scheider, grote witte tekst | +| `accent` | Groene slide met witte tekst | +| `light-blue` / `light-pink` / `light-green` / `light-orange` / `light-yellow` | Zachte gekleurde achtergrond | +| `dense` | Kleinere tabel/code/quote (0.70em) — bij veel inhoud | +| `dense-table` | Alleen tabel kleiner | +| `dense-code` | Alleen codeblok kleiner | + +`class` (zonder underscore) i.p.v. `_class` = geldt vanaf die slide tot je hem weer wijzigt. + +### Layout & helpers (rauwe HTML in de Markdown) + +```html +
+
… links …
+
… rechts …
+
+``` + +- `
85%
` — groot oranje kerngetal. +- `
` — blauwe subkop, gecentreerd. +- `

` — blauw→oranje gradient kader. + +### Kleuren (`--npuls-*` vars) + +oranje `#DD784B` · blauw `#3D68EC` · groen `#00AF81` · geel `#F4D74B` · roze `#F4D9DC`. +Standaard: H1/H2 oranje, `**strong**` en links blauw, tabel-header blauw met gestreepte rijen, +blockquote oranje linkerrand. + +## Stap 3 — Render & visueel controleren + +Render de **eindproducten** naar de `exports/`-submap. De `.md` blijft in de hoofdmap; de +`html`- én `pdf`-versies komen in `exports/`: + +```bash +mkdir -p exports +marp deck.md -o exports/deck.html +marp deck.md --pdf -o exports/deck.pdf +``` + +Beide bestanden zijn eindproducten en **blijven staan** in `exports/`. De PDF dient +tegelijk als overflow-check — niet meer weggooien. + +Lees de PDF met de **Read tool**, `pages "1-N"` (tot 20 per call), en controleer elke slide op: + +- inhoud die aan de onder-/rechterrand wordt **afgekapt** (overflow — Marp waarschuwt hier niet voor); +- tekst die te klein of te groot is; +- lege of onevenwichtige slides. + +**Fix overflow** in de `.md` en render opnieuw: +- veel tekst → splits de slide in twee, of ``; +- brede tabel → ``; +- lang codeblok → ``; +- naast elkaar → `columns`. + +Herhaal render → Read → fix tot alle slides schoon zijn. + +> `exports/*.html` en `exports/*.pdf` erven automatisch het `npuls`-thema — Marp bakt de CSS +> in elk bestand in. Geen aparte print-CSS nodig: de PDF-lay-out is identiek aan de HTML. + +### Stap 3b — PDF live-preview (wijzigingen direct zien) + +Wil je overflow live zien terwijl je bewerkt: render de PDF in **watch**-modus en open hem +in een viewer die automatisch herlaadt. + +```bash +marp deck.md --pdf -o exports/deck.pdf --watch +``` + +Start dit **in de achtergrond** (Bash `run_in_background: true`), open daarna de PDF: + +```bash +open exports/deck.pdf +``` + +- `--watch` re-rendert de PDF bij elke save van de `.md`. +- macOS **Preview** herlaadt een gewijzigde PDF meestal vanzelf; **Skim** doet dit het + betrouwbaarst (zet *Preferences → Sync → Check for file changes* aan). +- De HTML preview-server is sneller voor tekst en flow; de PDF-watch toont de **echte + paginaranden** en dus de overflow. + +Stoppen: `pkill -f "marp.*--watch"`. + +## Bestaande deck updaten + +Bij het wijzigen van een bestaande deck: **sla stap 1 over** — `npuls.css` en `.marprc.yml` +staan al naast de `.md`. Niet opnieuw kopiëren, niet overschrijven. + +1. Edit de `.md` gericht (Edit-tool, niet de hele file herschrijven). +2. Re-render beide eindproducten: `marp deck.md -o exports/deck.html && marp deck.md --pdf -o exports/deck.pdf`. +3. **Check alleen de geraakte slides** op overflow — lees de gewijzigde pagina's uit + `exports/deck.pdf` met de Read tool, fix waar nodig. De PDF blijft staan (geen opruimen). + +Grootste risico bij update: tekst toevoegen aan een bestaande slide duwt inhoud over de rand — +Marp clipt stil. Neem nooit aan dat een geraakte slide nog past; check hem visueel. + +## Gotchas + +- **Overflow is stil.** Marp clipt zonder error. Altijd visueel checken (stap 3). +- **`columns` vereist rauwe `
`-HTML**, geen Markdown-kolommen. +- **`_class` vs `class`**: underscore = deze slide; zonder = vanaf deze slide. +- **PDF/PNG-export vereist Chromium.** Chrome staat op deze Mac. Faalt export? Zet + `CHROME_PATH=/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` of geef `--browser chrome`. +- **Lokale fonts** (`General Sans`, `Cooper Light BT`) vallen netjes terug op Plus Jakarta Sans + als ze ontbreken — geen blocker. +- **Links/e-mails op donkere slides** (`accent`/`divider`/`title`) blijven blauw → laag contrast. + Schrijf contactgegevens als platte tekst, of vermijd links op gekleurde achtergronden. + +## Optioneel — programmatische overflow-check (Playwright/Chrome MCP) + +Wil je overflow detecteren zonder vision-tokens: open `deck.html` via een browser-MCP en meet +per `section` of `scrollHeight > clientHeight`. Krachtiger voor grote decks, maar vereist een +geconfigureerde MCP en mikken op Marp's bespoke DOM. De PDF+Read-loop hierboven is de standaard. + +## Benodigde permissies (verse machine) + +Voeg toe aan `~/.claude/settings.json` → `permissions.allow` voor prompt-vrij renderen: + +```json +"Bash(marp:*)", +"Bash(npx marp:*)", +"Bash(which marp)", +"Bash(brew install marp-cli:*)", +"Bash(open:*)", +"Bash(pkill:*)", +"Read(**/*.pdf)" +``` + +`Bash(marp:*)` dekt ook de preview-server (`marp --preview --server .`); `Bash(open:*)` opent de +deck-URL prompt-vrij; `Bash(pkill:*)` stopt de preview-server. + +`Read(**/*.pdf)` laat de PDF in `exports/` zonder prompt lezen. Het aanmaken van `exports/` +en het kopiëren van assets (`mkdir`/`cp`) blijft prompt-on-first-use — bewust niet breed. diff --git a/.claude/skills/build-marp-deck/assets/.marprc.yml b/.claude/skills/build-marp-deck/assets/.marprc.yml new file mode 100644 index 0000000..b32c59b --- /dev/null +++ b/.claude/skills/build-marp-deck/assets/.marprc.yml @@ -0,0 +1,2 @@ +themeSet: + - npuls.css diff --git a/.claude/skills/build-marp-deck/assets/_template.md b/.claude/skills/build-marp-deck/assets/_template.md new file mode 100644 index 0000000..7cc7e81 --- /dev/null +++ b/.claude/skills/build-marp-deck/assets/_template.md @@ -0,0 +1,89 @@ +--- +marp: true +theme: npuls +paginate: true +--- + + + +# Presentatietitel +## Ondertitel of claim + +CEDA / Npuls AI & Data — 2026 + +--- + +# Inhoud + +1. Waar staan we? +2. Het voorstel +3. Aanpak en planning +4. Bijlage + +--- + + + +# 1. Waar staan we? + +--- + +# Twee kolommen + +
+
+ +**Nu** + +- Lokaal en ad-hoc +- Geen gedeelde standaard +- Werk wordt dubbel gedaan + +
+
+ +**Straks** + +- Gedeelde standaarden +- Herbruikbare tooling +- Eén bron van waarheid + +
+
+ +--- + +# Een citaat + +> Standaardisatie is geen doel op zich, maar de voorwaarde voor schaal. + +Gewone tekst met **blauwe nadruk** en een [link](https://npuls.nl). + +--- + + + +# Tabel (dense voor veel rijen) + +| Onderdeel | Status | Eigenaar | +|------------------|--------------|----------| +| Architectuur | Concept | CEDA | +| Datastandaarden | In uitvoering| Npuls | +| Adoptie-toolkit | Gepland | CEDA | +| Pilots | Q3 2026 | Instellingen | + +--- + +# Eén groot getal + +
85%
+ +
van de instellingen wil samenwerken aan standaarden
+ +--- + + + +# Vragen? + +corneeldenhartogh@gmail.com diff --git a/.claude/skills/build-marp-deck/assets/npuls.css b/.claude/skills/build-marp-deck/assets/npuls.css new file mode 100644 index 0000000..ea5de51 --- /dev/null +++ b/.claude/skills/build-marp-deck/assets/npuls.css @@ -0,0 +1,252 @@ +/* @theme npuls */ +@import 'default'; + +@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600;700&display=swap'); + +@font-face { + font-family: 'General Sans'; + src: local('General Sans Regular'), local('GeneralSans-Regular'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'General Sans'; + src: local('General Sans Semibold'), local('GeneralSans-Semibold'); + font-weight: 600; + font-style: normal; +} + +@font-face { + font-family: 'Cooper Light BT'; + src: local('Cooper Light BT'), local('CooperLightBT'); + font-weight: 300; + font-style: normal; +} + +:root { + --npuls-orange: #DD784B; + --npuls-black: #000000; + --npuls-pink: #F4D9DC; + --npuls-blue: #3D68EC; + --npuls-yellow: #F4D74B; + --npuls-green: #00AF81; + --npuls-white: #FFFFFF; + + --npuls-green-light: #CCEEE6; + --npuls-blue-light: #D6E2FD; + --npuls-pink-light: #FAEAEA; + --npuls-orange-light: #FFE4D8; + --npuls-yellow-light: #FCF5D4; +} + +section { + font-family: 'General Sans', 'Plus Jakarta Sans', Arial, Helvetica, sans-serif; + font-size: 25px; + color: var(--npuls-black); + background-color: var(--npuls-white); + padding: 40px 50px; +} + +/* Headings */ + +section h1 { + color: var(--npuls-orange); + font-weight: 700; + line-height: 1.2; +} + +section h2 { + color: var(--npuls-orange); + font-weight: 600; +} + +section h3, +section h4, +section h5, +section h6 { + color: var(--npuls-black); + font-weight: 600; +} + +/* Typography */ + +section a { + color: var(--npuls-blue); + text-decoration: none; +} + +section a:hover { + color: var(--npuls-orange); +} + +section strong { + color: var(--npuls-blue); + font-weight: 600; +} + +section blockquote { + font-family: 'Cooper Light BT', 'Plus Jakarta Sans', Georgia, serif; + font-weight: 300; + border-left: 4px solid var(--npuls-orange); + padding: 0.5em 1em; + margin: 1em 0; + background-color: var(--npuls-orange-light); + color: var(--npuls-black); + font-size: 0.9em; +} + +/* Tables */ + +section table { + font-size: 0.85em; + width: 100%; + border-collapse: collapse; +} + +section table th { + background-color: var(--npuls-blue); + color: var(--npuls-white); + font-weight: 600; + padding: 0.4em 0.6em; + text-align: left; +} + +section table td { + padding: 0.4em 0.6em; + border-bottom: 1px solid #e0e0e0; +} + +section table tr:nth-child(even) { + background-color: var(--npuls-blue-light); +} + +/* Code blocks */ + +section pre { + text-align: center; + border-left: 4px solid var(--npuls-blue); + border-radius: 0.5rem; + background-color: #f8f9fa; +} + +section pre code { + display: inline-block; + text-align: left; +} + +section code { + color: var(--npuls-blue); +} + +/* Layout utilities */ + +section .columns { + display: flex; + gap: 2em; +} + +section .col { + flex: 1; +} + +/* Slide variants */ + +section.divider { + background-color: var(--npuls-orange); + color: var(--npuls-white); + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} + +section.divider h1 { + color: var(--npuls-white); + font-size: 2.5em; +} + +section.divider h2 { + color: var(--npuls-white); + font-weight: 400; +} + +section.title { + background-color: var(--npuls-blue); + color: var(--npuls-white); + text-align: center; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +section.title h1 { + color: var(--npuls-white); +} + +section.title h2 { + color: var(--npuls-pink); + font-weight: 400; +} + +section.accent { + background-color: var(--npuls-green); + color: var(--npuls-white); +} + +section.accent h1 { + color: var(--npuls-white); +} + +/* Light background variants */ + +section.light-blue { background-color: var(--npuls-blue-light); } +section.light-pink { background-color: var(--npuls-pink-light); } +section.light-green { background-color: var(--npuls-green-light); } +section.light-orange { background-color: var(--npuls-orange-light); } +section.light-yellow { background-color: var(--npuls-yellow-light); } + +/* Helper classes */ + +section .big-impact { + font-size: 3.5rem; + font-weight: 700; + color: var(--npuls-orange); + line-height: 1.1; + text-align: center; +} + +section .medium-impact { + font-size: 2rem; + font-weight: 600; + color: var(--npuls-blue); + text-align: center; +} + +section .highlight-box { + background: linear-gradient(135deg, var(--npuls-blue) 0%, var(--npuls-orange) 100%); + padding: 1rem; + border-radius: 0.75rem; + color: white; + text-align: center; +} + +section .highlight-box h3 { + color: white; +} + +/* Density helpers */ + +section.dense-table table { font-size: 0.70em; } +section.dense-code pre { font-size: 0.70em; } +section.dense table, +section.dense pre, +section.dense blockquote { font-size: 0.70em; } + +/* Pagination */ + +section::after { + color: var(--npuls-blue); + font-size: 0.7em; +} diff --git a/.claude/skills/generate-slides-retro-simple/SKILL.md b/.claude/skills/generate-slides-retro-simple/SKILL.md new file mode 100644 index 0000000..21843fc --- /dev/null +++ b/.claude/skills/generate-slides-retro-simple/SKILL.md @@ -0,0 +1,452 @@ +--- +name: generate-slides-retro-simple +description: Genereer een compacte, inhoudelijke Slidev sprint review presentatie voor CEDA, georganiseerd per domein (instroom/uitval/tech/project) met substantiemetriek op basis van commits, functies en het CEDA Board. +--- + +# generate-slides-retro-simple + +Genereer een compacte sprint review presentatie voor CEDA, georganiseerd per domein met focus op wat er daadwerkelijk is opgeleverd. + +## Instructies + +### Stap 0: Clone het clidev project + +1. Zoek of het project al ergens op de machine staat: + ```bash + find ~ -type f -name "_template.md" 2>/dev/null | xargs -I{} dirname {} | while read dir; do + [ -d "$dir/theme" ] && [ -d "$dir/public/npuls" ] && echo "$dir" + done | head -3 + ``` +2. Als het niet gevonden wordt, clone het: + ```bash + git clone https://github.com/cedanl/clidev-presentaties.git ~/clidev-presentaties + ``` +3. Installeer dependencies als `node_modules/` ontbreekt: + ```bash + cd && npm install + ``` +4. Genereer de presentatie **in deze directory** met `theme: ./theme`. Naamconventie: `YYMMDD_sprint_review_simple.md`. + +### Stap 1: GitHub Token check & sprint-periode + +**Token check — voer dit uit VOORDAT je data ophaalt:** +1. Controleer of `$GITHUB_TOKEN` is ingesteld (`echo $GITHUB_TOKEN`). +2. Als het NIET is ingesteld, vraag de gebruiker: + > Je hebt een GitHub Personal Access Token nodig. Heb je er al een? + > + > **Zo niet, maak er een aan:** + > 1. Ga naar https://github.com/settings/tokens + > 2. Klik op **"Generate new token (classic)"** + > 3. Selecteer minimaal de scopes **`repo`** en **`read:org`** en **`project`** + > 4. Klik op **"Generate token"** en kopieer het token + > + > **Plak je GitHub token hier in de chat:** +3. Zodra de gebruiker het token plakt: + ```bash + export GITHUB_TOKEN="" + ``` +4. Verifieer: + ```bash + curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | grep login + ``` + +**Iteratie-periode ophalen van CEDA Board:** + +Haal de actieve iteratie op van het CEDA Board (project #2) via GraphQL: + +```bash +gh api graphql -f query=' +{ + organization(login: "cedanl") { + projectV2(number: 2) { + field(name: "Iteratie") { + ... on ProjectV2IterationField { + configuration { + iterations { + id + title + startDate + duration + } + completedIterations { + id + title + startDate + duration + } + } + } + } + } + } +} +' +``` + +- Gebruik de huidige/meest recente iteratie om `SPRINT_START` en `SPRINT_END` te bepalen +- `SPRINT_START` = `startDate` van de iteratie +- `SPRINT_END` = `startDate` + `duration` dagen +- Het veld heet "Iteratie" (Nederlands), niet "Iteration" +- Als er geen iteratie-veld is, val terug op 2 weken eindigend op vandaag +- Toon de iteratie-titel (bijv. "Sprint 12") in de presentatie + +**Repo's ophalen en filteren:** +- Haal alle repos op: `curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/cedanl/repos?per_page=100&type=public"` +- Werk `config.json` bij met de resultaten. +- Pre-filter: alleen repo's waar `pushed_at >= SPRINT_START`. + +### Stap 2: Categorie-mapping + +Elke actieve repo wordt gemapt naar 1 van 5 domeinen: + +| Domein | Kleur | Repos (pattern match) | +|--------|-------|----------------------| +| **instroom** | `#1D76DB` | `*instroom*`, `*prognose*`, `student-instroom-mbo`, `dashboard-instroomprognose-mbo` | +| **uitval** | `#D93F0B` | `*1cijfer*`, `*1cho*`, `*uitval*`, `*vsv*`, `*uitnodiging*`, `no-fairness-without-awareness`, `lta-hhs-fairnessawareness`, `Assistentie`, `student-signal` | +| **tech** | `#5319E7` | `*template*`, `*devcontainer*`, `sdp-tools`, `ceda-scoop`, `maak_een_hex`, `docker_1cho` | +| **project** | `#0E8A16` | `project_algemeen`, `ceda-algemeen`, `communicatie`, `.github`, `clidev-presentaties`, `public_activities`, `centre_documentation`, `regiobijeenkomsten` | +| **overig** | `#757575` | `arbeidsmarkt-mbo`, `cbs-onderwijsdata`, `overzicht-landelijke-databronnen`, `samenwijzer`, `eencijfer`, `textanalysis` | + +Fallback voor onbekende repos: `overig`. + +### Stap 3: Data ophalen + +Haal 4 databronnen op voor alle actieve repo's: + +#### A. Commits op main + +Per actieve repo: +```bash +gh api "repos/cedanl/{repo}/commits?sha=main&since={SPRINT_START}&until={SPRINT_END}&per_page=100" \ + --jq '.[] | {sha: .sha, author: .author.login, message: .commit.message, date: .commit.author.date}' +``` + +Verzamel per repo: +- Totaal aantal commits +- Unieke contributors (GitHub usernames) +- Avatar URL per contributor: `https://github.com/{username}.png` + +#### B. CEDA Board status via GraphQL + +Haal alle items op van het CEDA Board (project #2) inclusief hun status: + +```bash +gh api graphql -f query=' +query($cursor: String) { + organization(login: "cedanl") { + projectV2(number: 2) { + items(first: 100, after: $cursor) { + nodes { + status: fieldValueByName(name: "Status") { + ... on ProjectV2ItemFieldSingleSelectValue { + name + } + } + iteratie: fieldValueByName(name: "Iteratie") { + ... on ProjectV2ItemFieldIterationValue { + title + } + } + content { + ... on Issue { + number + title + state + closedAt + url + body + repository { + name + } + issueType { + name + } + assignees(first: 5) { + nodes { + login + } + } + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } +} +' +``` + +**Let op:** gebruik GraphQL aliases (`status:` en `iteratie:`) omdat je twee `fieldValueByName` calls nodig hebt. + +Filter items op `iteratie.title == {huidige iteratie titel}` om alleen items van de actieve iteratie te tonen. + +Als `hasNextPage` true is, pagineer met `after: $endCursor`. + +Verzamel per board item: +- Status: Done / In Progress / Todo / On Hold +- Issue type: Pitch / Task / Bug (uit `issueType.name`) +- Repo naam (voor categorie-mapping) +- Assignees (voor avatars) +- `closedAt` (voor filtering op sprint-periode) +- `body` (voor scope-analyse bij Pitches) + +#### C. Functie-metric (20-100 regels) — alleen TOEGEVOEGDE code + +Per actieve repo met commits, haal de diff op: + +1. Bepaal het eerste commit SHA voor de sprint: +```bash +FIRST_SHA=$(gh api "repos/cedanl/{repo}/commits?sha=main&until={SPRINT_START}&per_page=1" --jq '.[0].sha') +``` + +2. Haal de compare op en filter op Python/R bestanden: +```bash +gh api "repos/cedanl/{repo}/compare/{FIRST_SHA}...main" \ + --jq '.files[] | select(.filename | test("\\.(py|R|r)$")) | {filename, patch}' +``` + +3. Analyseer alleen de `+` regels uit elke patch (toegevoegde code): + - **Python**: zoek naar `def ` blokken en tel regels tot het volgende `def`/`class` of dedent + - **R**: zoek naar `<- function(` of `= function(` blokken en tel regels tot de sluitende `}` + - Tel alleen functies van **20-100 regels** + +4. Dit is een proxy voor "echte logica toegevoegd" — niet boilerplate, niet one-liners, niet monolithen. + +5. Rapporteer per repo: "N functies (20-100 regels) toegevoegd" + +#### D. Bestanden geraakt + +Uit dezelfde compare API response: +```bash +gh api "repos/cedanl/{repo}/compare/{FIRST_SHA}...main" --jq '[.files[].filename] | length' +``` + +Context indicator (geen waardeoordeel): +- Breed (>20 bestanden) = feature/integratie werk +- Smal (<5 bestanden) = bugfix/refactor + +### Stap 4: Metrics berekenen + +1. **Opgeleverd**: Board items met Status=Done waarvan `closedAt` in de sprint-periode valt. Groepeer per type: + - Pitches afgerond + - Tasks afgerond + - Bugs afgerond + - **Ratio**: done / (done + in_progress + todo) — dit is de delivery ratio + +2. **Iteratie Output**: Totaal functies 20-100 regels per domein. + +3. **Scope per pitch**: Per Pitch op het board: + - Check de issue body voor tasklists: `- [ ]` (open) en `- [x]` (done) + - Check voor issue referenties (`#123`) in de body + - Tel done vs totaal sub-items + - Toont of een pitch echt af is of half + +4. **Bestanden geraakt**: Totaal unieke files per domein. + +### Stap 5: Genereer slides + +**BELANGRIJK: Geen `