Files
brain-template/scripts/brain-index-regen.sh
Tetardtek 878886cd51 feat: brain-template v2.0 — BSI-v3 complet + tiers documentés
- README reécrit : tiers free/pro/full + modèle clé API + multi-instance
- Sync agents/ (57 agents, kernel-isolation validated)
- Sync scripts/ BSI-v3 (file-lock, preflight, human-gate, brain-status)
- KERNEL.md v0.7.0 — zones + délégation + rendering + isolation
- brain-compose.yml v0.7.0 — rendering mode + kerneluser
- workflows/ — template + brain-engine exemple
- locks/.gitkeep + claims/.gitkeep
- helloWorld : RAG boot tier full only (bsi-rag retiré du template)
2026-03-16 23:26:38 +01:00

128 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# brain-index-regen.sh — Régénère la table ## Claims dans BRAIN-INDEX.md
# depuis les fichiers claims/sess-*.yml (BSI v3 — source unique de vérité)
#
# Gère les formats :
# v1 : name: + opened: + status:
# v2 : sess_id: + opened_at: + status:
# v3 : + satellite_type + zone (inféré) + result.status
#
# Usage : bash scripts/brain-index-regen.sh
# Appelé par : session-orchestrator (close sequence step 5)
# helloWorld (boot claim open)
#
# Anti-drift : lecture seule sur claims/*.yml — écriture uniquement sur BRAIN-INDEX.md ## Claims
# Sécurité : aucun secret dans les claims (garanti par secrets-guardian)
set -euo pipefail
BRAIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
CLAIMS_DIR="$BRAIN_ROOT/claims"
INDEX_FILE="$BRAIN_ROOT/BRAIN-INDEX.md"
if [[ ! -f "$INDEX_FILE" ]]; then
echo "❌ BRAIN-INDEX.md introuvable — chemin : $INDEX_FILE"
exit 1
fi
if [[ ! -d "$CLAIMS_DIR" ]]; then
echo "❌ claims/ introuvable — chemin : $CLAIMS_DIR"
exit 1
fi
# ── Parser tous les claims via Python (gère YAML multi-format proprement) ────
python3 - "$CLAIMS_DIR" "$INDEX_FILE" <<'PYEOF'
import sys, os, re
claims_dir = sys.argv[1]
index_path = sys.argv[2]
rows = []
open_count = 0
for filename in sorted(os.listdir(claims_dir)):
if not filename.startswith('sess-') or not filename.endswith('.yml'):
continue
filepath = os.path.join(claims_dir, filename)
with open(filepath, 'r') as f:
content = f.read()
def extract(pattern, text, default='—'):
m = re.search(pattern, text, re.MULTILINE)
if m:
return m.group(1).strip().strip('"\'')
return default
# Gère v1 (name:) et v2 (sess_id:)
def extract_first(*patterns):
for p in patterns:
m = re.search(p, content, re.MULTILINE)
if m:
return m.group(1).strip().strip('"\'')
return '—'
sess_id = extract_first(r'^sess_id:\s*(.+)', r'^name:\s*(sess-.+)')
scope = extract_first(r'^scope:\s*(.+)')
status = extract_first(r'^status:\s*(.+)')
opened = extract_first(r'^opened_at:\s*(.+)', r'^opened:\s*(.+)')
sat_type = extract_first(r'^satellite_type:\s*(.+)')
theme_br = extract_first(r'^theme_branch:\s*(.+)')
# Inférer zone depuis scope (BSI v3 — ADR-014)
KERNEL_SCOPES = ['agents/', 'profil/', 'scripts/', 'KERNEL.md',
'brain-constitution.md', 'brain-compose.yml']
PERSONAL_SCOPES = ['profil/capital', 'profil/objectifs', 'progression/', 'MYSECRETS']
zone = 'project'
for ks in KERNEL_SCOPES:
if ks in scope:
zone = 'kernel'
break
for ps in PERSONAL_SCOPES:
if ps in scope:
zone = 'personal'
break
# Résultat du close si disponible
result_status = extract(r'^\s+status:\s*(.+)', content)
if result_status in ('open', 'closed', 'stale', '—'):
result_status = '—'
# Indicateur satellite_type
type_display = sat_type if sat_type != '—' else '—'
theme_display = theme_br.replace('theme/', '') if theme_br != '—' else '—'
rows.append(f"| {sess_id} | {scope} | {status} | {opened} | {type_display} | {zone} | {result_status} |")
if status == 'open':
open_count += 1
table_rows = "\n".join(rows)
comment = ("<!-- ⚠️ TABLE GÉNÉRÉE — ne pas éditer manuellement.\n"
" Régénérée par : scripts/brain-index-regen.sh\n"
" Appelée par : session-orchestrator (close) + helloWorld (boot)\n"
" Source unique : claims/sess-*.yml (BSI v3) -->\n")
new_table = (f"{comment}Sessions actives à ce jour :\n\n"
f"| sess_id | scope | status | opened_at | type | zone | result |\n"
f"|---------|-------|--------|-----------|------|------|--------|\n"
f"{table_rows}")
# Lire BRAIN-INDEX.md
with open(index_path, 'r') as f:
content = f.read()
# Remplacer depuis le commentaire HTML (ou "Sessions actives") jusqu'au prochain "---"
# Deux patterns : avec ou sans commentaire généré
pattern = r'(?:<!--.*?-->\s*\n)?Sessions actives à ce jour :.*?(?=\n---)'
if not re.search(pattern, content, flags=re.DOTALL):
print("⚠️ Pattern claims non trouvé dans BRAIN-INDEX.md — pas de modification")
sys.exit(0)
new_content = re.sub(pattern, new_table, content, flags=re.DOTALL)
with open(index_path, 'w') as f:
f.write(new_content)
print(f"✅ BRAIN-INDEX.md régénéré — {open_count} claim(s) open / {len(rows)} total")
PYEOF