224 lines
6.6 KiB
Bash
Executable File
224 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# workflow-launch.sh — Lance le prochain step d'un workflow thématique
|
|
# Lit le workflow YAML, trouve le step à lancer, génère le claim BSI correspondant.
|
|
#
|
|
# Usage :
|
|
# bash scripts/workflow-launch.sh <workflow.yml> # step 1 (ou prochain)
|
|
# bash scripts/workflow-launch.sh <workflow.yml> --step N # step spécifique
|
|
# bash scripts/workflow-launch.sh <workflow.yml> --status # état de la chaîne
|
|
#
|
|
# Le claim est écrit dans brain.db (ADR-042) — l'humain lance le satellite.
|
|
# (Futur : kernel-orchestrator lancera automatiquement — BSI-v3-9)
|
|
|
|
set -euo pipefail
|
|
|
|
BRAIN_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)"
|
|
|
|
WORKFLOW_FILE="${1:-}"
|
|
MODE="launch"
|
|
TARGET_STEP=""
|
|
|
|
# --- Parse args ---
|
|
shift || true
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--step) TARGET_STEP="$2"; shift 2 ;;
|
|
--status) MODE="status"; shift ;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$WORKFLOW_FILE" ]; then
|
|
echo "Usage : bash scripts/workflow-launch.sh <workflow.yml> [--step N] [--status]"
|
|
echo "Workflows disponibles :"
|
|
ls "$BRAIN_ROOT/workflows/"*.yml 2>/dev/null | grep -v "_template" \
|
|
| sed "s|$BRAIN_ROOT/workflows/||" | sed 's/^/ /'
|
|
exit 1
|
|
fi
|
|
|
|
# Résolution chemin workflow
|
|
if [ ! -f "$WORKFLOW_FILE" ]; then
|
|
WORKFLOW_FILE="$BRAIN_ROOT/workflows/$WORKFLOW_FILE"
|
|
fi
|
|
if [ ! -f "$WORKFLOW_FILE" ]; then
|
|
echo "🚨 Workflow introuvable : $WORKFLOW_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Lecture du workflow (parser YAML minimal) ---
|
|
THEME_NAME=$(grep '^name:' "$WORKFLOW_FILE" | sed 's/name: *//' | tr -d '"')
|
|
THEME_BRANCH=$(grep '^branch:' "$WORKFLOW_FILE" | sed 's/branch: *//' | tr -d '"')
|
|
|
|
echo "📋 Workflow : $THEME_NAME"
|
|
echo " Branche : $THEME_BRANCH"
|
|
echo ""
|
|
|
|
# --- Mode status : afficher l'état de la chaîne (brain.db — ADR-042) ---
|
|
if [ "$MODE" = "status" ]; then
|
|
echo "État des claims pour ce thème :"
|
|
echo ""
|
|
python3 -c "
|
|
import sqlite3, sys
|
|
conn = sqlite3.connect('$BRAIN_ROOT/brain.db')
|
|
conn.row_factory = sqlite3.Row
|
|
rows = conn.execute(
|
|
'SELECT sess_id, status, workflow_step, result_status FROM claims WHERE theme_branch = ? ORDER BY workflow_step',
|
|
('$THEME_BRANCH',)
|
|
).fetchall()
|
|
conn.close()
|
|
if not rows:
|
|
print(' (aucun claim pour ce thème)')
|
|
for r in rows:
|
|
step = r['workflow_step'] or '?'
|
|
result = r['result_status'] or '-'
|
|
print(f\" Step {step} — {r['sess_id']} [{r['status']}] result:{result}\")
|
|
" 2>/dev/null || echo " ⚠️ brain.db inaccessible"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Trouver le prochain step à lancer ---
|
|
# Lire les steps depuis le workflow
|
|
STEPS=()
|
|
STEP_TYPES=()
|
|
STEP_SCOPES=()
|
|
STEP_ANGLES=()
|
|
STEP_GATES=()
|
|
|
|
current_step=""
|
|
current_type=""
|
|
current_scope=""
|
|
current_angle=""
|
|
current_gate=""
|
|
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ ^[[:space:]]*-[[:space:]]step:[[:space:]]*([0-9]+) ]]; then
|
|
# Sauvegarder le step précédent
|
|
if [ -n "$current_step" ]; then
|
|
STEPS+=("$current_step")
|
|
STEP_TYPES+=("$current_type")
|
|
STEP_SCOPES+=("$current_scope")
|
|
STEP_ANGLES+=("$current_angle")
|
|
STEP_GATES+=("$current_gate")
|
|
fi
|
|
current_step="${BASH_REMATCH[1]}"
|
|
current_type=""
|
|
current_scope=""
|
|
current_angle=""
|
|
current_gate=""
|
|
elif [[ "$line" =~ ^[[:space:]]+type:[[:space:]]*(.+) ]]; then
|
|
current_type="${BASH_REMATCH[1]}"
|
|
elif [[ "$line" =~ ^[[:space:]]+scope:[[:space:]]*(.+) ]]; then
|
|
current_scope="${BASH_REMATCH[1]}"
|
|
elif [[ "$line" =~ ^[[:space:]]+story_angle:[[:space:]]*\"(.+)\" ]]; then
|
|
current_angle="${BASH_REMATCH[1]}"
|
|
elif [[ "$line" =~ ^[[:space:]]+gate:[[:space:]]*(.+) ]]; then
|
|
current_gate="${BASH_REMATCH[1]}"
|
|
fi
|
|
done < "$WORKFLOW_FILE"
|
|
|
|
# Sauvegarder le dernier step
|
|
if [ -n "$current_step" ]; then
|
|
STEPS+=("$current_step")
|
|
STEP_TYPES+=("$current_type")
|
|
STEP_SCOPES+=("$current_scope")
|
|
STEP_ANGLES+=("$current_angle")
|
|
STEP_GATES+=("$current_gate")
|
|
fi
|
|
|
|
TOTAL_STEPS=${#STEPS[@]}
|
|
|
|
if [ "$TOTAL_STEPS" -eq 0 ]; then
|
|
echo "🚨 Aucun step trouvé dans le workflow."
|
|
exit 1
|
|
fi
|
|
|
|
# Déterminer le step cible
|
|
if [ -n "$TARGET_STEP" ]; then
|
|
STEP_IDX=$((TARGET_STEP - 1))
|
|
else
|
|
# Trouver le dernier step complété via brain.db (ADR-042)
|
|
LAST_DONE=$(python3 -c "
|
|
import sqlite3
|
|
conn = sqlite3.connect('$BRAIN_ROOT/brain.db')
|
|
r = conn.execute(
|
|
'SELECT MAX(workflow_step) FROM claims WHERE theme_branch = ? AND status = ?',
|
|
('$THEME_BRANCH', 'closed')
|
|
).fetchone()
|
|
conn.close()
|
|
print(r[0] if r[0] is not None else 0)
|
|
" 2>/dev/null || echo 0)
|
|
STEP_IDX=$LAST_DONE
|
|
fi
|
|
|
|
if [ "$STEP_IDX" -ge "$TOTAL_STEPS" ]; then
|
|
echo "✅ Workflow terminé — tous les steps complétés ($TOTAL_STEPS/$TOTAL_STEPS)"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Construire le claim pour ce step ---
|
|
STEP_NUM="${STEPS[$STEP_IDX]}"
|
|
STEP_TYPE="${STEP_TYPES[$STEP_IDX]}"
|
|
STEP_SCOPE="${STEP_SCOPES[$STEP_IDX]}"
|
|
STEP_ANGLE="${STEP_ANGLES[$STEP_IDX]}"
|
|
STEP_GATE="${STEP_GATES[$STEP_IDX]}"
|
|
|
|
# Déterminer le next step pour on_done
|
|
NEXT_IDX=$((STEP_IDX + 1))
|
|
ON_DONE=""
|
|
ON_FAIL="signal → BLOCKED_ON pilote"
|
|
|
|
if [ "$NEXT_IDX" -lt "$TOTAL_STEPS" ]; then
|
|
NEXT_TYPE="${STEP_TYPES[$NEXT_IDX]}"
|
|
NEXT_SCOPE="${STEP_SCOPES[$NEXT_IDX]}"
|
|
NEXT_GATE="${STEP_GATES[$NEXT_IDX]}"
|
|
|
|
if [ "$NEXT_GATE" = "human" ]; then
|
|
ON_DONE="gate:human → \"Step $((NEXT_IDX+1)) prêt ($NEXT_TYPE:$NEXT_SCOPE) — lancer ?\""
|
|
else
|
|
ON_DONE="trigger → type:$NEXT_TYPE scope:$NEXT_SCOPE"
|
|
fi
|
|
else
|
|
ON_DONE="notify → pilote # dernier step — chaîne terminée"
|
|
fi
|
|
|
|
# Gestion gate sur le step courant
|
|
if [ "$STEP_GATE" = "human" ]; then
|
|
echo "⏸ GATE HUMAN requis avant ce step."
|
|
echo " Confirmer avant de lancer le satellite."
|
|
echo ""
|
|
fi
|
|
|
|
# Générer le sess_id
|
|
DATETIME=$(date +%Y%m%d-%H%M)
|
|
SCOPE_SLUG=$(echo "$STEP_SCOPE" | tr '/' '-' | sed 's/-$//' | tr '[:upper:]' '[:lower:]')
|
|
SESS_ID="sess-${DATETIME}-${THEME_NAME}-step${STEP_NUM}"
|
|
|
|
# Écrire le claim dans brain.db (ADR-042 — source unique)
|
|
bash "$BRAIN_ROOT/scripts/bsi-claim.sh" open "$SESS_ID" \
|
|
--scope "$STEP_SCOPE" --type "satellite" --zone "project" \
|
|
--story "$STEP_ANGLE" --mode "$STEP_TYPE"
|
|
|
|
# Enrichir avec les champs workflow spécifiques
|
|
python3 -c "
|
|
import sqlite3
|
|
conn = sqlite3.connect('$BRAIN_ROOT/brain.db')
|
|
conn.execute('''
|
|
UPDATE claims SET satellite_type = ?, satellite_level = 'leaf',
|
|
theme_branch = ?, workflow = ?, workflow_step = ?
|
|
WHERE sess_id = ?
|
|
''', ('$STEP_TYPE', '$THEME_BRANCH', '$THEME_NAME', $STEP_NUM, '$SESS_ID'))
|
|
conn.commit()
|
|
conn.close()
|
|
" 2>/dev/null
|
|
|
|
echo ""
|
|
echo " Step : $STEP_NUM / $TOTAL_STEPS"
|
|
echo " Type : $STEP_TYPE"
|
|
echo " Scope : $STEP_SCOPE"
|
|
echo " Tâche : $STEP_ANGLE"
|
|
if [ -n "$STEP_GATE" ]; then
|
|
echo " Gate : $STEP_GATE"
|
|
fi
|
|
echo " On done : $ON_DONE"
|
|
echo " On fail : $ON_FAIL"
|