From 3ce08fe91e875a850d5dfd5bae3a3230299f5e83 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Fri, 3 Jul 2026 17:44:19 +0200 Subject: [PATCH] v19: git-baseret konsumtion - forberedelse til privat repo Beslutning: BCQuality skal vaere privat. En fork af et offentligt repo kan ikke goeres privat, saa flyttet sker via detach/nyoprettelse - men FOERST omlaegges al konsumtion fra tokenfri raw-URLs til git-baseret adgang, shippet mens kanalen stadig er offentlig, saa flaaden aldrig oplever et hul. GCM er token-haandteringen: udviklerne er allerede autentificeret. Kernen er KANAL-KLONEN: %USERPROFILE%\.claude\BCQuality, pinned til stable. Alt kopieres derfra (filsystem-kopi = raa bytes; ingen CDN-cache, ingen API-limits). - sync-bcquality-knowledge.ps1 v2: git-baseret (klon/fetch/checkout stable, mirror bygges lokalt, skriver selv versionsmarkoeren) - Install-CurabisMachine.ps1 v2: onboarding = git clone + script fra klonen; foerste GCM-login ER autentificeringen - curabis-standard.agent.md v19: SRC/BASE-tokens peger paa klonen; fetch betyder copy; Mode B Step 0 freshener klonen; ny Mode B- sektion opdaterer maskin-CLAUDE.md ved konsumtionsmodel-skift (gated, Identity bevares); CLAUDE.md-templatens self-heals er git-baserede - machine/CLAUDE.md v2: auto-update gater paa git fetch/rev-parse i stedet for GitHub API; setup laeses fra klonen - Ishikawa + al-triage + Francis: fallbacks peger paa mirror/klon; al-triages hardcodede URL-liste fjernet (samme sygdom som Ishikawa havde). Aerlig konsekvens: Copilot mister live custom-fallback - CONSUMPTION.md: Access model-sektion + to-linjers onboarding - Invoke-CurabisEvidence: RawBase markeret legacy/doed Nul raw.githubusercontent-referencer tilbage i forbrugerkritiske filer. Co-Authored-By: Claude Fable 5 --- CONSUMPTION.md | 25 ++-- custom/agents/francis.agent.md | 7 +- custom/scripts/Invoke-CurabisEvidence.ps1 | 6 +- custom/setup/curabis-standard.agent.md | 67 +++++++++-- custom/setup/machine/CLAUDE.md | 42 +++++-- .../setup/machine/Install-CurabisMachine.ps1 | 64 +++++----- custom/setup/sync-bcquality-knowledge.ps1 | 109 ++++++++---------- custom/setup/templates/al-triage.agent.md | 13 +-- custom/setup/templates/bcquality.agent.md | 11 +- 9 files changed, 205 insertions(+), 139 deletions(-) diff --git a/CONSUMPTION.md b/CONSUMPTION.md index d4db2a6..b3d5dda 100644 --- a/CONSUMPTION.md +++ b/CONSUMPTION.md @@ -38,22 +38,31 @@ future CI/PR-review integration: currently consumed by nothing. Keep it — but do not mistake it for active configuration of the session model. +## Access model: PRIVATE repo, git-based consumption + +BCQuality is a **private** repository. All consumption is git-based through +the **channel clone** at `%USERPROFILE%\.claude\BCQuality`, pinned to the +`stable` branch. Authentication is Git Credential Manager — the developer's +existing GitHub login; the first git contact opens a browser login, and that +is the entire token story. `raw.githubusercontent.com` and unauthenticated +GitHub-API calls are dead and must not appear in any consumer. + ## Machine onboarding (new developer) -A fresh developer machine is made CURABIS-ready with ONE command -(idempotent — safe to re-run): +Two lines (idempotent — safe to re-run; the clone prompts the GCM login): - powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/machine/Install-CurabisMachine.ps1 -OutFile $env:TEMP\icm.ps1; & $env:TEMP\icm.ps1" + git clone --branch stable --single-branch https://github.com/Curabis/BCQuality.git "$env:USERPROFILE\.claude\BCQuality" + powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\BCQuality\custom\setup\machine\Install-CurabisMachine.ps1" It installs the global CLAUDE.md (identity substituted from git config), bc-mcp-bridge.js, the bc-mcp config template (the developer inserts their personal client secret), the knowledge sync script, and syncs the machine -mirror. Per repo afterwards: "Opdater CURABIS Standard fra BCQuality" — it -deploys `.vscode/find-altool.ps1` (a CURABIS template; no VS Code command -generates it) and the AL MCP wiring itself. The AL Language extension from -the Marketplace is the only per-machine prerequisite for AL MCP. +mirror from the clone. Per repo afterwards: "Opdater CURABIS Standard fra +BCQuality" — it deploys `.vscode/find-altool.ps1` and the AL MCP wiring +itself. The AL Language extension from the Marketplace is the only +per-machine prerequisite for AL MCP. -**Auto-trigger:** the command above rarely needs to be run by hand. Every +**Auto-trigger:** the lines above rarely need to be run by hand. Every project CLAUDE.md (setup v15+) carries a machine self-heal: any Claude Code session in any configured CURABIS repo detects an un-onboarded machine (missing `~/.claude/CLAUDE.md` or bridge) and runs the onboarding itself — diff --git a/custom/agents/francis.agent.md b/custom/agents/francis.agent.md index e6435bf..3d38e6e 100644 --- a/custom/agents/francis.agent.md +++ b/custom/agents/francis.agent.md @@ -76,10 +76,9 @@ reviews what happened. He asks one question about every significant event: > "Er der en BCQuality-regel der ville have fanget dette? Dækkede den fuldt ud?" -He compares against the full BCQuality knowledge base: -``` -BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge -``` +He compares against the full BCQuality knowledge base — the machine-local +mirror at `%USERPROFILE%\.claude\bcquality-knowledge\custom\` (fallback: the +channel clone `%USERPROFILE%\.claude\BCQuality\custom\knowledge\`). Domains: `architecture/`, `testing/`, `mcp/` ## The Two Proposal Types diff --git a/custom/scripts/Invoke-CurabisEvidence.ps1 b/custom/scripts/Invoke-CurabisEvidence.ps1 index 498eafe..6a6f84c 100644 --- a/custom/scripts/Invoke-CurabisEvidence.ps1 +++ b/custom/scripts/Invoke-CurabisEvidence.ps1 @@ -28,8 +28,10 @@ param( # Lokal BCQuality-klon. Default: proev ..\bcquality og .\.bcquality. [string]$BCQualityHome, - # Bruges naar der ikke er en lokal klon: knowledge-filer HTTP-tjekkes herfra. - [string]$RawBase = 'https://raw.githubusercontent.com/Curabis/BCQuality/stable', + # LEGACY: repoet er privat - raw-URLs virker ikke laengere. Brug altid en + # lokal klon; kanal-klonen findes paa alle onboardede maskiner: + # -BCQualityHome "$env:USERPROFILE\.claude\BCQuality" + [string]$RawBase = '', [switch]$Quiet ) diff --git a/custom/setup/curabis-standard.agent.md b/custom/setup/curabis-standard.agent.md index ba73b19..9598afa 100644 --- a/custom/setup/curabis-standard.agent.md +++ b/custom/setup/curabis-standard.agent.md @@ -1,7 +1,7 @@ --- kind: action-skill id: curabis-standard-setup -version: 18 +version: 19 title: CURABIS Standard — Project Setup description: > Configures a new or existing repository to the CURABIS Standard development @@ -34,14 +34,33 @@ This agent runs when the developer says any of: Detect which mode based on the trigger phrase and proceed accordingly. -## Source URLs (BCQuality — always fetch fresh) +## Source: the channel clone (BCQuality is PRIVATE — no raw URLs) + +All artifacts come from the machine's **channel clone** — a git clone of +`Curabis/BCQuality` pinned to the `stable` branch. Authentication is Git +Credential Manager (the developer's existing GitHub login); there are NO +tokenless raw.githubusercontent fetches anywhere — the repo is private. ``` -BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup -AGENTS_BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/agents +SRC = %USERPROFILE%\.claude\BCQuality (kanal-klonen, stable) +BASE = {SRC}\custom\setup +AGENTS_BASE = {SRC}\custom\agents ``` -| Artefakt | URL | +**Before ANY Mode A/B work, ensure the channel clone is fresh:** + + git -C "$env:USERPROFILE\.claude\BCQuality" fetch origin stable --quiet + git -C "$env:USERPROFILE\.claude\BCQuality" checkout -B stable origin/stable --quiet + +If the clone is missing entirely: + + git clone --branch stable --single-branch https://github.com/Curabis/BCQuality.git "$env:USERPROFILE\.claude\BCQuality" + +**Vocabulary:** wherever this document says "fetch", it means **copy the file +from SRC** — a filesystem copy, which preserves raw bytes by definition (the +old HTTP-encoding pitfalls do not exist here). + +| Artefakt | Placering | |---|---| | bc-mcp-bridge.js | `{BASE}/bc-mcp-bridge.js` | | bc-mcp.config.template.json | `{BASE}/machine/bc-mcp.config.template.json` | @@ -188,10 +207,13 @@ covers every repo, and the repo history stays free of upstream rule churn. **Machine self-heal (auto-onboarding):** if this machine is not CURABIS- onboarded — `~/.claude/CLAUDE.md` or `~/.claude/bc-mcp-bridge.js` is missing — -run the full onboarding NOW (idempotent; identity taken from git config): +run the full onboarding NOW (idempotent; identity taken from git config; the +first git contact may open a browser login — that IS the authentication): - powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/machine/Install-CurabisMachine.ps1 -OutFile $env:TEMP\icm.ps1; & $env:TEMP\icm.ps1" + git clone --branch stable --single-branch https://github.com/Curabis/BCQuality.git "$env:USERPROFILE\.claude\BCQuality" + powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\BCQuality\custom\setup\machine\Install-CurabisMachine.ps1" +(Skip the clone line if `%USERPROFILE%\.claude\BCQuality` already exists.) Then report the manual leftovers it lists (personal client secret; the AL Language extension if VS Code lacks it) and ask the developer to restart Claude Code. @@ -201,7 +223,9 @@ self-heal suffices: powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1" -(If that sync script itself is missing, the full onboarding above installs it.) +(If that sync script itself is missing, copy it from the channel clone: +`%USERPROFILE%\.claude\BCQuality\custom\setup\sync-bcquality-knowledge.ps1` — +or run the full onboarding above.) These rules are always active. @@ -520,6 +544,10 @@ Co-Authored-By: Claude Sonnet 4.6 Triggered by: "Opdater CURABIS Standard fra BCQuality" +**Step 0 — freshen the channel clone** (see Source section): fetch + checkout +`origin/stable` in `%USERPROFILE%\.claude\BCQuality`; create the clone if +missing. Every copy below reads from that clone. + Updates only the files that come directly from BCQuality. Never touches `CLAUDE.md`, `projectmemory/`, `docs/`, or `~/.bc-mcp.config.json`. @@ -600,10 +628,24 @@ Detect and clean up: - a reference to `.github/.agents/bcquality-knowledge/` (v6 repo-mirror era) - a literal per-developer path such as `C:\Users\\.claude\...` — must be `~/.claude/...` / `%USERPROFILE%`, never one developer's username + - ANY remaining `raw.githubusercontent.com`-based self-heal or onboarding + command (v15-v18 era) — the repo is private; raw URLs are dead. The + current form is git-based via the channel clone. If any match, propose replacing the section with the current template from Step 4a and ask for confirmation before editing CLAUDE.md (same confirmation gate as the agent-synligheds-check below). +### Machine CLAUDE.md refresh (Mode B) + +The developer's global `~/.claude/CLAUDE.md` carries the CURABIS auto-update +instructions. After a consumption-model change (like v19's git migration), +those instructions go stale on every already-onboarded machine. Compare the +machine file's CURABIS sections against `{BASE}/machine/CLAUDE.md` in the +channel clone. If they diverge structurally (e.g. still reference raw URLs +or GitHub-API SHA checks), propose the update — show the diff, preserve the +Identity section verbatim, and ask for confirmation before editing: it is the +developer's personal file. + ### .mcp.json — hardcoded developer-path validation (Mode B) `.mcp.json` is git-committed and shared — it must not contain a path baked in for @@ -735,6 +777,9 @@ Co-Authored-By: Claude Sonnet 4.6 ## Invocation note -This agent is fetched on demand from BCQuality. Both commands work in any -project — including one not yet configured — because Claude reads the URL -from `~/.claude/CLAUDE.md` (global instructions, present on all CURABIS machines). \ No newline at end of file +This agent is read on demand from the machine's channel clone +(`%USERPROFILE%\.claude\BCQuality\custom\setup\curabis-standard.agent.md`, +after freshening — see Source section). Both commands work in any project — +including one not yet configured — because the machine's `~/.claude/CLAUDE.md` +(installed by onboarding) knows the clone location. On a machine without the +clone, the two-line onboarding in Step 4a's self-heal is the entry point. \ No newline at end of file diff --git a/custom/setup/machine/CLAUDE.md b/custom/setup/machine/CLAUDE.md index aa59f2a..84bad3f 100644 --- a/custom/setup/machine/CLAUDE.md +++ b/custom/setup/machine/CLAUDE.md @@ -2,30 +2,54 @@ # CURABIS — Global Claude Code Instructions These instructions apply to every Claude Code session, regardless of project. +BCQuality is a PRIVATE repo: all access is git-based via the channel clone at +`%USERPROFILE%\.claude\BCQuality` (pinned to `stable`; auth = Git Credential +Manager). No raw.githubusercontent URLs — they do not work and must not be used. ## Auto-update BCQuality (runs at every session start) If the current project has `.github/.agents/bcquality.agent.md`: -1. Fetch the latest commit SHA for `custom/setup/` in BCQuality: - `https://api.github.com/repos/Curabis/BCQuality/commits?path=custom/setup&sha=stable&per_page=1` +1. Freshen the channel clone and read its SHA: + `git -C "$env:USERPROFILE\.claude\BCQuality" fetch origin stable --quiet` + `git -C "$env:USERPROFILE\.claude\BCQuality" rev-parse origin/stable` + (If the clone is missing: run the machine self-heal from the project + CLAUDE.md — two lines: git clone + Install-CurabisMachine.ps1.) 2. Read stored SHA from `~/.claude/.bcquality-version` (may not exist yet) 3. If SHA is different (or file missing): - a. Fetch and execute Mode B from: - `https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/curabis-standard.agent.md` - b. Write new SHA to `~/.claude/.bcquality-version` - c. Report: "BCQuality opdateret til [short-sha] — [antal] filer tjekket" -4. If SHA is unchanged: continue silently + a. `git -C "$env:USERPROFILE\.claude\BCQuality" checkout -B stable origin/stable --quiet` + b. Execute Mode B from the clone: + `%USERPROFILE%\.claude\BCQuality\custom\setup\curabis-standard.agent.md` + c. Refresh the local knowledge mirror: + `powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1"` + (git-based; also writes the new SHA to the version marker) + d. Report: "BCQuality opdateret til [short-sha] — [antal] filer tjekket" +4. If SHA is unchanged: continue silently — do NOT re-run the sync script. One + sync per actual upstream change covers every project worked on until the next one. Do this silently and quickly — do not ask for permission, do not explain the process unless something actually changed. +## BCQuality knowledge files — session start + +At session start, read BCQuality rules from the local cache (fast — no network): + +- **`custom/`** — always read in full: `%USERPROFILE%\.claude\bcquality-knowledge\custom\**\*.md` +- **`community/`** and **`microsoft/`** — do NOT read in full (200+ files is too + much to preload). Instead read `%USERPROFILE%\.claude\bcquality-knowledge\INDEX.md` + first, and open only the files whose domain/keywords match the current task. + +If the cache directory is missing or empty: run +`powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1"` +once, then proceed as above. + ## CURABIS Standard project setup -When the user says either of these commands, fetch and follow the setup agent: +When the user says either of these commands, freshen the channel clone (see +Auto-update step 1) and follow the setup agent read from: ``` -https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/curabis-standard.agent.md +%USERPROFILE%\.claude\BCQuality\custom\setup\curabis-standard.agent.md ``` - **"Konfigurer dette projekt til CURABIS Standard"** → fuld setup af nyt repo diff --git a/custom/setup/machine/Install-CurabisMachine.ps1 b/custom/setup/machine/Install-CurabisMachine.ps1 index 83f7430..e569617 100644 --- a/custom/setup/machine/Install-CurabisMachine.ps1 +++ b/custom/setup/machine/Install-CurabisMachine.ps1 @@ -1,16 +1,16 @@ -# CURABIS maskin-onboarding - goer en frisk udviklermaskine klar til -# CURABIS Standard. Koeres EEN gang pr. maskine; er idempotent (sikker at -# koere igen). Alt hentes som raa bytes fra stable-kanalen. +# CURABIS maskin-onboarding v2 (GIT-BASERET, privat repo) - goer en frisk +# udviklermaskine CURABIS-klar. Idempotent; sikker at koere igen. # -# Torsten (eller enhver ny udvikler) koerer: -# powershell -ExecutionPolicy Bypass -File Install-CurabisMachine.ps1 +# Onboarding paa en ny maskine er TO linjer (GCM-login i browseren ved +# foerste git-kontakt ER autentificeringen): # -# Eller direkte fra BCQuality: -# powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/machine/Install-CurabisMachine.ps1 -OutFile $env:TEMP\icm.ps1; & $env:TEMP\icm.ps1" +# git clone --branch stable --single-branch https://github.com/Curabis/BCQuality.git "$env:USERPROFILE\.claude\BCQuality" +# powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\BCQuality\custom\setup\machine\Install-CurabisMachine.ps1" # -# Hvad der IKKE haandteres her (personligt/manuel): -# - din client secret i ~/.bc-mcp.config.json (scriptet lægger templaten -# og siger til) +# Alt kopieres fra kanal-klonen (filsystem-kopi = raa bytes; ingen raw-URLs). +# +# Haandteres IKKE her (personligt/manuelt): +# - din client secret i ~/.bc-mcp.config.json (templaten laegges, du udfylder) # - VS Code + AL Language-extensionen (ms-dynamics-smb.al fra Marketplace) param( [string]$FullName, @@ -18,11 +18,21 @@ param( ) $ErrorActionPreference = 'Stop' -$raw = 'https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup' $claude = Join-Path $env:USERPROFILE '.claude' +$clone = Join-Path $env:USERPROFILE '.claude\BCQuality' New-Item -ItemType Directory -Force $claude | Out-Null -# Identitet: default fra git config, ellers spoerg +# Kilde: scriptet ligger i \custom\setup\machine → klonrod tre niveauer op +$src = (Resolve-Path (Join-Path $PSScriptRoot '..\..\..')).Path + +# Sikr kanal-klonen paa den kanoniske placering (scriptet KAN vaere koert fra en anden klon) +if (-not (Test-Path (Join-Path $clone '.git'))) { + if ($src -ne $clone) { + git clone --branch stable --single-branch 'https://github.com/Curabis/BCQuality.git' $clone + if ($LASTEXITCODE -ne 0) { throw 'git clone af kanal-klonen fejlede - tjek adgang/GCM.' } + } +} + if (-not $FullName) { $FullName = (git config user.name 2>$null) } if (-not $UserName) { $UserName = $env:USERNAME } if (-not $FullName) { $FullName = Read-Host 'Dit fulde navn' } @@ -30,12 +40,12 @@ if (-not $FullName) { $FullName = Read-Host 'Dit fulde navn' } $done = @() $todo = @() -# 1. Global CLAUDE.md (fra template; overskriver ALDRIG en eksisterende) +# 1. Global CLAUDE.md (fra template i klonen; overskriver ALDRIG en eksisterende) $gcm = Join-Path $claude 'CLAUDE.md' if (Test-Path $gcm) { - $done += "CLAUDE.md fandtes allerede - ikke roert" + $done += 'CLAUDE.md fandtes allerede - ikke roert' } else { - Invoke-WebRequest -UseBasicParsing "$raw/machine/CLAUDE.md" -OutFile $gcm + Copy-Item (Join-Path $src 'custom\setup\machine\CLAUDE.md') $gcm $t = [System.IO.File]::ReadAllText($gcm) $t = $t.Replace('[Your Name]', $FullName).Replace('[your-username]', $UserName) $t = $t -replace '\r?\n', '' @@ -44,29 +54,22 @@ if (Test-Path $gcm) { } # 2. BC MCP bridge (stable er autoritativ - overskriv) -Invoke-WebRequest -UseBasicParsing "$raw/bc-mcp-bridge.js" -OutFile (Join-Path $claude 'bc-mcp-bridge.js') -$done += "bc-mcp-bridge.js installeret" +Copy-Item (Join-Path $src 'custom\setup\bc-mcp-bridge.js') (Join-Path $claude 'bc-mcp-bridge.js') -Force +$done += 'bc-mcp-bridge.js installeret' # 3. BC MCP config-template (personlig secret - aldrig overskrive) $cfg = Join-Path $env:USERPROFILE '.bc-mcp.config.json' if (Test-Path $cfg) { - $done += "bc-mcp.config.json fandtes allerede - ikke roert" + $done += 'bc-mcp.config.json fandtes allerede - ikke roert' } else { - Invoke-WebRequest -UseBasicParsing "$raw/machine/bc-mcp.config.template.json" -OutFile $cfg + Copy-Item (Join-Path $src 'custom\setup\machine\bc-mcp.config.template.json') $cfg $todo += "Aabn $cfg og indsaet din personlige client secret" } -# 4. Knowledge-sync-script + mirror -Invoke-WebRequest -UseBasicParsing "$raw/sync-bcquality-knowledge.ps1" -OutFile (Join-Path $claude 'sync-bcquality-knowledge.ps1') +# 4. Sync-script til maskinen + koer det (bygger mirror + saetter versionsmarkoer) +Copy-Item (Join-Path $src 'custom\setup\sync-bcquality-knowledge.ps1') (Join-Path $claude 'sync-bcquality-knowledge.ps1') -Force & powershell -ExecutionPolicy Bypass -File (Join-Path $claude 'sync-bcquality-knowledge.ps1') -$done += "bcquality-knowledge mirror synkroniseret" - -# 5. Versionsmarkoer (stable-SHA) -try { - $sha = (Invoke-RestMethod 'https://api.github.com/repos/Curabis/BCQuality/commits?sha=stable&per_page=1')[0].sha - Set-Content -Path (Join-Path $claude '.bcquality-version') -Value $sha -Encoding ascii - $done += "versionsmarkoer sat ($($sha.Substring(0,7)))" -} catch { $todo += "Kunne ikke saette versionsmarkoer (GitHub API) - foerste session goer det selv" } +$done += 'bcquality-knowledge mirror synkroniseret (git-baseret)' Write-Host '' Write-Host '=== CURABIS maskin-onboarding faerdig ===' -ForegroundColor Green @@ -78,5 +81,4 @@ if ($todo) { } Write-Host '' Write-Host 'Pr. repo herefter: sig "Opdater CURABIS Standard fra BCQuality" i Claude' -Write-Host 'Code - den deployer selv .vscode/find-altool.ps1 og AL MCP-opsaetningen.' -Write-Host 'Genstart Claude Code efter foerste onboarding.' +Write-Host 'Code - den henter alt fra kanal-klonen. Genstart Claude Code foerst.' diff --git a/custom/setup/sync-bcquality-knowledge.ps1 b/custom/setup/sync-bcquality-knowledge.ps1 index 0814226..2205a7f 100644 --- a/custom/setup/sync-bcquality-knowledge.ps1 +++ b/custom/setup/sync-bcquality-knowledge.ps1 @@ -1,36 +1,47 @@ # Refresh the MACHINE-LOCAL mirror of the Curabis BCQuality knowledge base. # -# Mirrors three layers from https://github.com/Curabis/BCQuality: +# v2 - GIT-BASED (privat repo): al konsumtion sker via en kanal-klon i +# %USERPROFILE%\.claude\BCQuality (pinned til stable-branchen) +# Autentificering haandteres af Git Credential Manager - ingen raw-URLs, +# ingen GitHub API, ingen CDN-cache. Foerste koersel udloeser evt. et +# GCM-login i browseren; det ER onboarding-autentificeringen. +# +# Mirrors three layers into %USERPROFILE%\.claude\bcquality-knowledge: # custom/ - Curabis org-specific rules (ALWAYS read in full each session) # community/ - BC community patterns (loaded on relevance via INDEX.md) # microsoft/ - platform guardrails (loaded on relevance via INDEX.md) +# ...plus INDEX.md (domain + keywords per fil) og opdaterer versionsmarkoeren. # -# The upstream file list is discovered dynamically from the GitHub tree API, so -# new/removed upstream files propagate automatically - nothing is hardcoded. -# After downloading, an INDEX.md is generated (one line per file, with domain + -# keywords from each file's frontmatter) so an agent can scan and pull only the -# files relevant to a task instead of loading all ~100 every session. -# -# The mirror is per developer machine (~/.claude/bcquality-knowledge/), shared -# by every CURABIS repo on it. It is NEVER committed to a project repository - -# see BCQuality rule bcquality-knowledge-must-mirror-to-machine-not-repo. -# One sync per machine covers every repo. Run periodically: +# Mirroren committes ALDRIG til et projekt-repo - se BCQuality-reglen +# bcquality-knowledge-must-mirror-to-machine-not-repo. Koer periodisk: # powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1" $ErrorActionPreference = 'Stop' -$repo = 'Curabis/BCQuality' -$branch = 'stable' +$repoUrl = 'https://github.com/Curabis/BCQuality.git' +$clone = Join-Path $env:USERPROFILE '.claude\BCQuality' $dest = Join-Path $env:USERPROFILE '.claude\bcquality-knowledge' +$marker = Join-Path $env:USERPROFILE '.claude\.bcquality-version' $staging = "$dest.tmp" -$rawBase = "https://raw.githubusercontent.com/$repo/$branch" -$treeUrl = "https://api.github.com/repos/$repo/git/trees/$branch" + '?recursive=1' -# Upstream path prefix -> local layer folder +# --- 1. Kanal-klon: opret eller opdater (pinned til stable) --- +if (-not (Test-Path (Join-Path $clone '.git'))) { + Write-Host "Kanal-klon mangler - kloner stable fra $repoUrl ..." + git clone --branch stable --single-branch $repoUrl $clone + if ($LASTEXITCODE -ne 0) { throw "git clone fejlede - er du autentificeret (GCM), og har du adgang til repoet?" } +} else { + git -C $clone fetch origin stable --quiet + if ($LASTEXITCODE -ne 0) { throw "git fetch fejlede - tjek netvaerk/adgang." } + git -C $clone checkout -B stable origin/stable --quiet +} +$sha = (git -C $clone rev-parse HEAD).Trim() +Write-Host "Kanal-klon paa stable @ $($sha.Substring(0,7))" + +# --- 2. Byg mirror fra klonens filer (ingen netvaerk herfra) --- $layerMap = [ordered]@{ - 'custom/knowledge/' = 'custom' - 'community/knowledge/' = 'community' - 'microsoft/knowledge/' = 'microsoft' + 'custom\knowledge' = 'custom' + 'community\knowledge' = 'community' + 'microsoft\knowledge' = 'microsoft' } function Get-Frontmatter { @@ -47,50 +58,25 @@ function Get-Frontmatter { return $fm } -Write-Host "Fetching file tree from $repo@$branch ..." -$headers = @{ 'User-Agent' = 'wareco-bcquality-sync'; 'Accept' = 'application/vnd.github+json' } -$tree = (Invoke-RestMethod -Uri $treeUrl -Headers $headers).tree - -# Build the download worklist from the tree -$files = @() -foreach ($node in $tree) { - if ($node.type -ne 'blob') { continue } - if ($node.path -notlike '*.md') { continue } - foreach ($prefix in $layerMap.Keys) { - if ($node.path.StartsWith($prefix)) { - $relative = $node.path.Substring($prefix.Length) # e.g. performance/avoid-commit-inside-loops.md - $files += [pscustomobject]@{ - Url = "$rawBase/$($node.path)" - Layer = $layerMap[$prefix] - Relative = $relative - LocalPath = Join-Path $staging (Join-Path $layerMap[$prefix] $relative) - } - break - } - } -} - -if ($files.Count -eq 0) { throw 'No knowledge files found in upstream tree - aborting.' } - -# Download into a staging folder so a mid-run failure never wipes the live copy if (Test-Path $staging) { Remove-Item -Recurse -Force $staging } New-Item -ItemType Directory -Force $staging | Out-Null -Write-Host "Downloading $($files.Count) knowledge files ..." -$rc = 0 -foreach ($f in $files) { - New-Item -ItemType Directory -Force (Split-Path $f.LocalPath) | Out-Null - try { - Invoke-WebRequest -Uri $f.Url -OutFile $f.LocalPath -UseBasicParsing -ErrorAction Stop - Write-Host "OK $($f.Layer)/$($f.Relative)" - } catch { - Write-Error "FAIL $($f.Layer)/$($f.Relative)" - $rc = 1 +$files = @() +foreach ($prefix in $layerMap.Keys) { + $srcDir = Join-Path $clone $prefix + if (-not (Test-Path $srcDir)) { continue } + $layer = $layerMap[$prefix] + Get-ChildItem $srcDir -Recurse -Filter *.md | ForEach-Object { + $relative = $_.FullName.Substring($srcDir.Length + 1) + $localPath = Join-Path $staging (Join-Path $layer $relative) + New-Item -ItemType Directory -Force (Split-Path $localPath) | Out-Null + Copy-Item $_.FullName $localPath + $files += [pscustomobject]@{ Layer = $layer; Relative = $relative; LocalPath = $localPath } } } +if ($files.Count -eq 0) { throw 'Ingen knowledge-filer fundet i kanal-klonen - afbryder.' } -# Generate INDEX.md (relevance index for all layers) -Write-Host "Generating INDEX.md ..." +# --- 3. INDEX.md (relevans-indeks for alle lag) --- $idx = [System.Collections.Generic.List[string]]::new() $idx.Add('# BCQuality Knowledge Index') $idx.Add('') @@ -100,7 +86,6 @@ $idx.Add('Layers: `custom` is ALWAYS read in full each session. For `community` $idx.Add('`microsoft`, scan this index and read only the files whose domain/keywords') $idx.Add('match the task at hand.') $idx.Add('') - foreach ($layer in @('custom', 'community', 'microsoft')) { $layerFiles = $files | Where-Object { $_.Layer -eq $layer } | Sort-Object Relative if (-not $layerFiles) { continue } @@ -111,18 +96,18 @@ foreach ($layer in @('custom', 'community', 'microsoft')) { $fm = Get-Frontmatter $f.LocalPath $domain = if ($fm.ContainsKey('domain')) { $fm['domain'] } else { '' } $keywords = if ($fm.ContainsKey('keywords')) { $fm['keywords'].Trim('[', ']') } else { '' } - $rel = $f.Relative -replace '\.md$', '' + $rel = ($f.Relative -replace '\.md$', '') -replace '\\', '/' $idx.Add("- ``$layer/$rel`` - domain: $domain; keywords: $keywords") } $idx.Add('') } Set-Content -Path (Join-Path $staging 'INDEX.md') -Value $idx -Encoding utf8 -# Swap staging into place +# --- 4. Swap + markoer --- if (Test-Path $dest) { Remove-Item -Recurse -Force $dest } Rename-Item -Path $staging -NewName (Split-Path $dest -Leaf) +Set-Content -Path $marker -Value $sha -Encoding ascii Write-Host '' -Write-Host "Done. $($files.Count) files across $($layerMap.Count) layers." +Write-Host "Done. $($files.Count) filer, 3 lag, stable @ $($sha.Substring(0,7))." Write-Host "Machine-local mirror updated: $dest" -exit $rc diff --git a/custom/setup/templates/al-triage.agent.md b/custom/setup/templates/al-triage.agent.md index ed8168f..40d0fec 100644 --- a/custom/setup/templates/al-triage.agent.md +++ b/custom/setup/templates/al-triage.agent.md @@ -56,14 +56,11 @@ Loop: **reproduce -> root-cause -> minimal-fix recommendation.** Layer 1 - Microsoft BCQuality: https://github.com/microsoft/BCQuality -Layer 2 - CURABIS custom knowledge (fetch before citing a finding): -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/pages-must-not-contain-business-logic.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/namespace-must-be-verified-from-source.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/al-identifiers-must-be-english.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/clarify-before-building.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-setup-must-use-library-codeunit.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-data-must-be-random-and-complete.md -- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/tests-must-adapt-to-existing-code.md +Layer 2 - CURABIS custom knowledge: read from the machine-local mirror — +`%USERPROFILE%\.claude\bcquality-knowledge\custom\` (always complete; never a +hardcoded file list — the rulebook grows). Fallback without a mirror: the +channel clone at `%USERPROFILE%\.claude\BCQuality\custom\knowledge\`. The +repo is PRIVATE — raw URLs do not exist. If a source is unreachable, **degrade gracefully**: fall back to the triage protocol below plus the CURABIS-ARCH rules in `bcquality.agent.md`, note that BCQuality was diff --git a/custom/setup/templates/bcquality.agent.md b/custom/setup/templates/bcquality.agent.md index e8b31ee..17a46ac 100644 --- a/custom/setup/templates/bcquality.agent.md +++ b/custom/setup/templates/bcquality.agent.md @@ -54,10 +54,13 @@ Resolve the current rule set at review time, in this order: `~/.claude/bcquality-knowledge/custom/` (Windows: `%USERPROFILE%\.claude\bcquality-knowledge\custom\`). The mirror is synced from the `stable` release channel and is always the complete custom layer. -2. **Fallback (no mirror — Copilot, fresh machine, CI):** list the tree via - `https://api.github.com/repos/Curabis/BCQuality/git/trees/stable?recursive=1` - filtered to `custom/knowledge/**/*.md`, and fetch each file from - `https://raw.githubusercontent.com/Curabis/BCQuality/stable/`. +2. **Fallback (no mirror):** read directly from the machine's channel clone — + `%USERPROFILE%\.claude\BCQuality\custom\knowledge\**\*.md` (freshen with + `git -C "$env:USERPROFILE\.claude\BCQuality" pull` if stale). The repo is + PRIVATE: tree-API/raw-URL fallbacks no longer exist. Consumers without + filesystem access outside the workspace (e.g. Copilot) rely on the + repo-committed agent files alone — deep custom-layer lookups happen in + Claude Code sessions. Relevance filtering: `custom/` rules are always active in CURABIS repos — read them all; use each file's frontmatter `domain`/`keywords` only to prioritize,