devzone 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,12 +12,20 @@ set -euo pipefail
12
12
  ETAT="${DEVZONE_ETAT:-$HOME/.config/devzone/modules}"
13
13
  ICI="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
14
14
  VERSIONS="$ICI/../core/scripts/versions.sh"
15
+ # Dossier de devzone (/workspaces/devzone) ; DEVZONE_RACINE pour les tests
16
+ RACINE="${DEVZONE_RACINE:-$(dirname "$ICI")}"
15
17
  MODULES=(ia kubernetes)
16
18
 
17
19
  # Assistants IA, versions figées : mettre à jour ici, puis devzone appliquer
18
- # (ou Rebuild Container)
19
- IA_PAQUETS=(@anthropic-ai/claude-code@2.1.286 opencode-ai@1.18.34)
20
- IA_NOMS=(@anthropic-ai/claude-code opencode-ai)
20
+ # (ou Rebuild Container). Une ligne par paquet, séparées par une ligne qui ne
21
+ # change pas : deux montées simultanées (workflow versions) se fusionnent sans
22
+ # conflit, git n'en signalant qu'entre lignes voisines modifiées.
23
+ # Claude Code
24
+ IA_CLAUDE=@anthropic-ai/claude-code@2.1.310
25
+ # opencode
26
+ IA_OPENCODE=opencode-ai@1.19.4
27
+ IA_PAQUETS=("$IA_CLAUDE" "$IA_OPENCODE")
28
+ IA_NOMS=("${IA_CLAUDE%@*}" "${IA_OPENCODE%@*}")
21
29
 
22
30
  description() {
23
31
  case "$1" in
@@ -98,9 +106,51 @@ config_opencode() {
98
106
  fi
99
107
  }
100
108
 
109
+ # Lance une commande longue en écrivant « toujours en cours » toutes les
110
+ # DEVZONE_PROGRESSION s sur stderr : une installation muette semble bloquée (#195)
111
+ avec_progression() {
112
+ local pas="${DEVZONE_PROGRESSION:-30}" ecoule=0 pid code=0
113
+ "$@" &
114
+ pid=$!
115
+ while kill -0 "$pid" 2>/dev/null; do
116
+ sleep 1
117
+ ecoule=$((ecoule + 1))
118
+ if [ $((ecoule % pas)) -eq 0 ] && kill -0 "$pid" 2>/dev/null; then
119
+ echo "devzone : … toujours en cours (${ecoule} s)" >&2
120
+ fi
121
+ done
122
+ wait "$pid" || code=$?
123
+ return "$code"
124
+ }
125
+
126
+ # Fichier qui marque un module actif en échec (contenu : où regarder) ; à côté
127
+ # de l'état, dans son volume : l'état l'affiche à chaque démarrage
128
+ fichier_echec() {
129
+ echo "$ETAT-echec-$1"
130
+ }
131
+
132
+ # Journal du dernier npm (son chemin est à donner en cas d'échec), ou son
133
+ # dossier ; noms horodatés : le dernier dans l'ordre du glob est le plus récent
134
+ dernier_journal_npm() {
135
+ local journal="" f
136
+ for f in "$HOME"/.npm/_logs/*-debug-0.log; do
137
+ if [ -f "$f" ]; then journal="$f"; fi
138
+ done
139
+ echo "${journal:-$HOME/.npm/_logs}"
140
+ }
141
+
101
142
  appliquer_ia() {
143
+ local journal
102
144
  if [ "$1" = on ]; then
103
- npm install -g --no-fund --no-audit --loglevel=error "${IA_PAQUETS[@]}" >/dev/null
145
+ echo "devzone : installation de Claude Code et opencode (quelques minutes)…"
146
+ if ! avec_progression npm install -g --no-fund --no-audit --loglevel=error "${IA_PAQUETS[@]}" >/dev/null; then
147
+ journal="$(dernier_journal_npm)"
148
+ echo "journal npm : $journal" >"$(fichier_echec ia)"
149
+ echo "devzone : échec de l'installation de ${IA_PAQUETS[*]} (npm install -g) ; journal npm : $journal ; réessayer : devzone appliquer" >&2
150
+ return 1
151
+ fi
152
+ rm -f "$(fichier_echec ia)"
153
+ echo "devzone : Claude Code et opencode installés"
104
154
  # Garde-fou repowarden (hook PreToolUse de Claude Code, plugin opencode) :
105
155
  # agent arrêté avant de modifier main/develop, de commiter sans
106
156
  # repowarden cc ou de contourner les hooks. Global, dans les volumes
@@ -114,6 +164,7 @@ appliquer_ia() {
114
164
  echo "devzone : ia actif : claude (puis /login), opencode auth login"
115
165
  else
116
166
  npm uninstall -g "${IA_NOMS[@]}" >/dev/null 2>&1 || true
167
+ rm -f "$(fichier_echec ia)"
117
168
  echo "devzone : ia désactivé (connexions gardées dans leurs volumes)"
118
169
  fi
119
170
  }
@@ -142,15 +193,36 @@ appliquer_repowarden() {
142
193
  ligne="$(bash "$VERSIONS" --installees 2>/dev/null | awk '$1 == "repowarden"' || true)"
143
194
  [ -n "$ligne" ] || return 0
144
195
  read -r _ figee installee <<<"$ligne"
196
+ echo "devzone : installation de repowarden $figee…"
145
197
  npm install -g "repowarden@$figee" >/dev/null
146
198
  repowarden install --global --lang fr
147
199
  echo "devzone : repowarden $installee → $figee"
148
200
  }
149
201
 
202
+ # Chemins des worktrees du dépôt devzone et des dépôts du workspace absents
203
+ # ici : créés de l'autre côté (hôte), un git worktree prune les casserait.
204
+ # Lecture seule : rien n'est supprimé ni réparé.
205
+ worktrees_absents() {
206
+ local depot ligne chemin
207
+ {
208
+ [ -e "$RACINE/.git" ] && echo "$RACINE"
209
+ find "$RACINE/workspace" -mindepth 2 -maxdepth 3 -name .git -type d 2>/dev/null | sed 's|/\.git$||'
210
+ } | while IFS= read -r depot; do
211
+ { git -C "$depot" worktree list --porcelain 2>/dev/null || true; } | while IFS= read -r ligne; do
212
+ case "$ligne" in
213
+ "worktree "*)
214
+ chemin="${ligne#worktree }"
215
+ [ -d "$chemin" ] || echo "$chemin"
216
+ ;;
217
+ esac
218
+ done
219
+ done || true
220
+ }
221
+
150
222
  # État complet : ✔ prêt, ✖ nécessaire, ○ facultatif, ⚠ à corriger ; chaque
151
223
  # point à faire avec sa commande (affiché à chaque démarrage)
152
224
  etat() {
153
- local nom email statut m retards
225
+ local nom email statut m retards chemin
154
226
  echo "devzone : état (devzone pour le réafficher)"
155
227
  nom="$(git config --get user.name || true)"
156
228
  email="$(git config --get user.email || true)"
@@ -177,8 +249,14 @@ etat() {
177
249
  done <<<"$retards"
178
250
  fi
179
251
  fi
252
+ while IFS= read -r chemin; do
253
+ [ -n "$chemin" ] || continue
254
+ echo " ⚠ worktree $chemin absent ici (créé hors du conteneur ?) : le gérer de ce côté-là, jamais git worktree prune ici (docs/reference.md, Worktrees git)"
255
+ done < <(worktrees_absents)
180
256
  for m in "${MODULES[@]}"; do
181
- if [ "$(valeur "$m")" = on ]; then
257
+ if [ "$(valeur "$m")" = on ] && [ -f "$(fichier_echec "$m")" ]; then
258
+ printf ' ✖ module %-10s en échec : installation incomplète (%s) : devzone appliquer\n' "$m" "$(cat "$(fichier_echec "$m")")"
259
+ elif [ "$(valeur "$m")" = on ]; then
182
260
  printf ' ✔ module %-10s actif : %s\n' "$m" "$(description "$m")"
183
261
  else
184
262
  printf ' ○ module %-10s facultatif, %s : devzone activer %s\n' "$m" "$(description "$m")" "$m"
@@ -46,13 +46,16 @@ git config --global url.https://github.com/.insteadOf git@github.com:
46
46
 
47
47
  # repowarden, version figée (il installe des hooks git globaux) ; mettre à jour
48
48
  # en changeant la version ici, puis Rebuild Container
49
- npm install -g repowarden@4.12.0
49
+ echo "devzone : installation de repowarden…"
50
+ npm install -g repowarden@4.12.1
50
51
  repowarden install --global --lang fr
51
52
 
52
53
  # Modules facultatifs (assistants IA, Kubernetes) : commande devzone, état
53
- # gardé dans le volume devzone-config ; installe ce qui est actif
54
+ # gardé dans le volume devzone-config ; installe ce qui est actif. Un module
55
+ # en échec n'arrête pas la création : le conteneur reste utilisable et l'état
56
+ # (devzone, à chaque démarrage) le montre « en échec »
54
57
  sudo ln -sf /workspaces/devzone/.devcontainer/devzone /usr/local/bin/devzone
55
- devzone appliquer
58
+ devzone appliquer || echo "devzone : modules incomplets (détail ci-dessus), réessayer : devzone appliquer" >&2
56
59
 
57
60
  # Ce qui reste à faire (identité git, GitHub, modules) : récapitulatif de
58
61
  # devzone, affiché à chaque démarrage (demarrage.sh)
package/README.md CHANGED
@@ -110,6 +110,7 @@ Ces modules sont désactivés par défaut, activables à la demande depuis le co
110
110
 
111
111
  ## Questions fréquentes
112
112
 
113
+ - **Docker absent ou arrêté** : `npx devzone`, `make up`, `make rebuild` et `make desinstaller` vérifient Docker avant tout et disent quoi faire : l'installer (Docker Desktop, ou Docker Engine sous Linux), démarrer Docker Desktop, ou, sous Linux, ajouter ton compte au groupe `docker` (`sudo usermod -aG docker $USER`, puis une nouvelle session). Avec `npx devzone mon-devzone`, le dossier est créé quand même : une fois Docker démarré, `cd mon-devzone && make shell`.
113
114
  - **Le premier lancement est long** : c'est normal (construction de l'image, téléchargement des images de base). Il prend 4 à 5 min mesurées, plus le téléchargement des images de base sur une machine neuve.
114
115
  - **`make` est absent sous Windows** : tu peux utiliser `npx @devcontainers/cli` (voir le tableau « Au quotidien ») ou Git Bash. Les scripts sont compatibles (fins de ligne LF).
115
116
  - **Pas de cluster Kubernetes visible** : devzone ne crée jamais de cluster. Avec le module `kubernetes` actif, il tente de se connecter à celui de l'hôte. Sinon, crée un cluster local avec `kind create cluster`.
package/core/devzone CHANGED
@@ -66,6 +66,13 @@ EOF
66
66
  echo "Pour le lancer : cd $cible && make up"
67
67
  return 0
68
68
  fi
69
+ # Docker d'abord : le dossier reste prêt, à lancer une fois Docker démarré
70
+ # shellcheck source=SCRIPTDIR/scripts/docker.sh
71
+ . "$PAQUET/core/scripts/docker.sh"
72
+ if ! docker_pret "cd $cible && make shell"; then
73
+ echo " Le dossier est prêt : rien à refaire, sauf ce lancement." >&2
74
+ exit 1
75
+ fi
69
76
  echo "▶ Lancement (quelques minutes la première fois)…"
70
77
  if command -v make >/dev/null 2>&1; then
71
78
  make -C "$cible" up
@@ -91,7 +98,7 @@ case "${1:-}" in
91
98
  echo "✖ À lancer dans un dossier devzone (desinstaller.sh introuvable ici)." >&2
92
99
  exit 1
93
100
  fi
94
- bash "$desinstalleur"
101
+ DEVZONE_COMMANDE="devzone desinstaller" bash "$desinstalleur"
95
102
  ;;
96
103
  -*)
97
104
  echo "✖ option inconnue : $1 (devzone --help)" >&2
@@ -24,6 +24,11 @@ case "$GARDER" in "" | connexions) ;; *)
24
24
  ;;
25
25
  esac
26
26
 
27
+ # Docker d'abord : sans lui, chaque appel docker afficherait son erreur brute
28
+ # shellcheck source=SCRIPTDIR/docker.sh
29
+ . "$(dirname "${BASH_SOURCE[0]}")/docker.sh"
30
+ docker_pret "${DEVZONE_COMMANDE:-make desinstaller}" || exit 1
31
+
27
32
  # --- Inventaire --------------------------------------------------------------
28
33
  echo "▶ Inventaire (dossier $ICI)"
29
34
  conteneurs=() images=() dind=()
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env bash
2
+ # Vérification de Docker sur l'hôte, avant tout appel (sourcé par lancer.sh,
3
+ # desinstaller.sh et la commande npm core/devzone) : sans elle, l'utilisateur
4
+ # ne voit que l'erreur brute du CLI devcontainers ou de docker.
5
+ # DEVZONE_DOCKER : nom de la commande docker (tests : simuler son absence).
6
+ # Compatible bash 3.2 (macOS).
7
+
8
+ # Code 0 si Docker répond ; sinon, sur stderr, la cause (absent, sans droits,
9
+ # arrêté) et quoi faire, puis relancer $1 ; code 1. Rien de brut à l'écran.
10
+ docker_pret() {
11
+ local commande="$1" docker="${DEVZONE_DOCKER:-docker}" erreur
12
+ if ! command -v "$docker" >/dev/null 2>&1; then
13
+ {
14
+ echo "✖ Docker introuvable : devzone en a besoin pour faire tourner son conteneur."
15
+ echo " Installe Docker Desktop (macOS, Windows, Linux) : https://docs.docker.com/desktop/"
16
+ echo " ou, sous Linux, Docker Engine : https://docs.docker.com/engine/install/"
17
+ echo " puis relance $commande"
18
+ } >&2
19
+ return 1
20
+ fi
21
+ erreur="$("$docker" info 2>&1 >/dev/null)" && return 0
22
+ case "$erreur" in
23
+ *"permission denied"* | *"Permission denied"*)
24
+ {
25
+ echo "✖ Docker refuse l'accès : ton compte n'est pas dans le groupe docker."
26
+ echo " sudo usermod -aG docker \$USER, puis ouvre une nouvelle session (ou newgrp docker),"
27
+ echo " puis relance $commande"
28
+ } >&2
29
+ ;;
30
+ *)
31
+ {
32
+ echo "✖ Docker est installé mais ne répond pas (arrêté ?)."
33
+ echo " Démarre Docker Desktop (sous Linux sans Docker Desktop : sudo systemctl start docker),"
34
+ echo " puis relance $commande"
35
+ } >&2
36
+ ;;
37
+ esac
38
+ return 1
39
+ }
@@ -80,6 +80,11 @@ arreter() {
80
80
  }
81
81
  trap 'arreter; echo; echo "interrompu — journal : .devzone.log"; exit 130' INT TERM
82
82
 
83
+ # Docker d'abord : sans lui, le CLI ne donnerait qu'une erreur JSON brute
84
+ # shellcheck source=SCRIPTDIR/docker.sh
85
+ . "$(dirname "${BASH_SOURCE[0]}")/docker.sh"
86
+ docker_pret "${DEVZONE_COMMANDE:-make $mode}" || exit 1
87
+
83
88
  : >"$LOG"
84
89
  debut="$(date +%s)"
85
90
  derniere_annonce="$debut"
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  # Versions figées du conteneur : compare repowarden (post-create.sh) et les
3
- # assistants IA (IA_PAQUETS, devzone) à la dernière version npm, ou applique
3
+ # assistants IA (lignes IA_…, devzone) à la dernière version npm, ou applique
4
4
  # une montée.
5
5
  # bash core/scripts/versions.sh
6
6
  # une ligne « paquet ancienne nouvelle » par paquet en retard, rien sinon
@@ -17,18 +17,17 @@ ICI="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
17
17
  POST_CREATE="$ICI/.devcontainer/post-create.sh"
18
18
  DEVZONE="$ICI/.devcontainer/devzone"
19
19
 
20
- # Liste « paquet version » des versions figées dans les deux fichiers
20
+ # Liste « paquet version » des versions figées dans les deux fichiers ; dans
21
+ # devzone, une ligne IA_<NOM>=<paquet>@<version> par assistant IA
21
22
  figees() {
22
23
  local ligne element
23
24
  ligne="$(sed -nE 's/.*npm install -g (repowarden)@([^[:space:]]+).*/\1 \2/p' "$POST_CREATE" | head -1)"
24
25
  [ -z "$ligne" ] || echo "$ligne"
25
- ligne="$(sed -nE 's/^IA_PAQUETS=\((.*)\)/\1/p' "$DEVZONE" | head -1)"
26
- [ -n "$ligne" ] || return 0
27
- for element in $ligne; do
26
+ while read -r element; do
28
27
  case "$element" in
29
- *@*) echo "${element%@*} ${element##*@}" ;;
28
+ ?*@*) echo "${element%@*} ${element##*@}" ;;
30
29
  esac
31
- done
30
+ done < <(sed -nE 's/^IA_[A-Z0-9_]+=([^[:space:]()"]+)$/\1/p' "$DEVZONE")
32
31
  }
33
32
 
34
33
  # Vrai si la version $1 est plus récente que $2 (composants numériques)
@@ -140,7 +139,7 @@ appliquer() {
140
139
  { echo "versions : paquet inconnu : $paquet" >&2; exit 1; }
141
140
  motif="$(echapper "$paquet")"
142
141
  tmp="$(mktemp)"
143
- sed -E "s|(${motif}@)[^ )]+|\1${version}|" "$fichier" >"$tmp"
142
+ sed -E "s|^(IA_[A-Z0-9_]+=${motif}@)[^[:space:]]+$|\1${version}|" "$fichier" >"$tmp"
144
143
  fi
145
144
  cat "$tmp" >"$fichier"
146
145
  rm -f "$tmp"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devzone",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Zone de dev conteneurisée : Java, Node, Python, Docker, Kubernetes et outils repowarden, dans un devcontainer",
5
5
  "license": "GPL-3.0-only",
6
6
  "repository": {