repowarden 4.9.3-next.1 → 4.10.0-next.4

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.
package/README.md CHANGED
@@ -22,6 +22,7 @@
22
22
  - **Formatage** : seul le contenu stagé, avec l'outil du projet ; le travail en cours est préservé.
23
23
  - **Tests** : au push et en CI, seulement les projets touchés, sur le commit poussé.
24
24
  - **Code mort** : seul le nouveau code mort est signalé, prouvé (bloquant) ou candidat (à vérifier) ; `repowarden code-mort` en local.
25
+ - **Agents IA** : Claude Code et opencode arrêtés avant de modifier une branche protégée, de travailler hors ticket ou de contourner les hooks, avec la commande à lancer ; `repowarden agents init`.
25
26
  - **Tickets** : chaque PR est reliée à un ticket validé (créé automatiquement s'il manque), suivi de « à valider » à « done » à la release ; `repowarden tickets init`.
26
27
  - **Versions et releases** : les commits étant conventionnels, la version suivante (semver) et le changelog se déduisent de l'historique ; un workflow réutilisable en fait des releases automatiques (PR de release validée par la CI puis mergée, tag, release), sans jeton ; dans le flux `develop` → `main`, un clic d'approbation par livraison.
27
28
 
@@ -95,7 +96,7 @@ Sans Node : `git clone https://github.com/simdevWarden/repowarden.git ~/repoward
95
96
  > [!NOTE]
96
97
  > **GitHub CLI (`gh`) : facultatif.**
97
98
  > Sans `gh` : tous les hooks (commits, branches, secrets, formatage, tests), `git cc`, `repowarden code-mort`, `repowarden statut`, et la CI (GitHub ou GitLab), qui n'utilise jamais le `gh` du poste.
98
- > Avec `gh` connecté (`gh auth login`), en plus : les tickets (`repowarden ticket`, `tickets`, branches de tes tickets créées en local) et la gestion du dépôt (`proteger`, `app init`, `npm-publication`, `pr-*`, `run-*`). Utile au mainteneur du dépôt GitHub ; chaque commande le signale s'il manque.
99
+ > Avec `gh` connecté (`gh auth login -s workflow` : le scope `workflow` autorise la modification de `.github/workflows/`), en plus : les tickets (`repowarden ticket`, `tickets`, branches de tes tickets créées en local) et la gestion du dépôt (`proteger`, `app init`, `npm-publication`, `pr-*`, `run-*`). Utile au mainteneur du dépôt GitHub ; chaque commande le signale s'il manque.
99
100
 
100
101
  ### 2. Dans un projet d'équipe : les mêmes règles pour tous
101
102
 
@@ -164,6 +165,6 @@ Les PR visent `develop` ; `main` ne reçoit que les livraisons, qui déclenchent
164
165
 
165
166
  ## Liens
166
167
 
167
- [Démarrage rapide](https://simdevwarden.github.io/repowarden/demarrage/) · [Hooks et règles](https://simdevwarden.github.io/repowarden/hooks/) · [Technologies](https://simdevwarden.github.io/repowarden/technologies/) · [Configuration](https://simdevwarden.github.io/repowarden/configuration/) · [CI](https://simdevwarden.github.io/repowarden/ci/) · [Versions et releases](https://simdevwarden.github.io/repowarden/releases/) · [Validation humaine](https://simdevwarden.github.io/repowarden/validation/) · [Code mort](https://simdevwarden.github.io/repowarden/code-mort/) · [En organisation](https://simdevwarden.github.io/repowarden/industrialisation/) · [Sources internes (Nexus, Artifactory)](https://simdevwarden.github.io/repowarden/industrialisation/#8-sources-internes-reseau-ferme-nexus-artifactory) · [Désinstallation](https://simdevwarden.github.io/repowarden/desinstallation/) · [Sécurité](SECURITY.md) · [Contribuer](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
168
+ [Démarrage rapide](https://simdevwarden.github.io/repowarden/demarrage/) · [Hooks et règles](https://simdevwarden.github.io/repowarden/hooks/) · [Technologies](https://simdevwarden.github.io/repowarden/technologies/) · [Configuration](https://simdevwarden.github.io/repowarden/configuration/) · [CI](https://simdevwarden.github.io/repowarden/ci/) · [Versions et releases](https://simdevwarden.github.io/repowarden/releases/) · [Validation humaine](https://simdevwarden.github.io/repowarden/validation/) · [Code mort](https://simdevwarden.github.io/repowarden/code-mort/) · [Agents IA](https://simdevwarden.github.io/repowarden/agents/) · [En organisation](https://simdevwarden.github.io/repowarden/industrialisation/) · [Sources internes (Nexus, Artifactory)](https://simdevwarden.github.io/repowarden/industrialisation/#8-sources-internes-reseau-ferme-nexus-artifactory) · [Désinstallation](https://simdevwarden.github.io/repowarden/desinstallation/) · [Sécurité](SECURITY.md) · [Contribuer](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
168
169
 
169
170
  Licence [GPL-3.0-only](LICENSE) : GNU General Public License version 3.
package/bin/agents ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env bash
2
+ # Branche le garde-fou repowarden (repowarden garde) dans les agents IA :
3
+ # repowarden agents init [--claude] [--opencode] [--projet | --global]
4
+ # Claude Code hook PreToolUse dans .claude/settings.json
5
+ # opencode plugin .opencode/plugins/repowarden-garde.js
6
+ # Sans --claude ni --opencode : les deux. --projet (défaut) : fichiers du dépôt,
7
+ # à versionner ; --global : configuration de l'utilisateur. Relançable :
8
+ # fichiers existants complétés, jamais écrasés.
9
+ set -euo pipefail
10
+
11
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
12
+ # shellcheck source=../hooks/lib/common.sh
13
+ source "$ROOT/hooks/lib/common.sh"
14
+
15
+ aide() { _tr help.agents; printf '%b\n' "$_T"; }
16
+
17
+ MODELE_OPENCODE="$ROOT/hooks/agents/repowarden-garde.js"
18
+ COMMANDE_CLAUDE="repowarden garde --format claude"
19
+ MATCHER_CLAUDE="Edit|Write|MultiEdit|NotebookEdit|Bash"
20
+
21
+ case "${1:-}" in
22
+ init) shift ;;
23
+ "" | -h | --help) aide; exit 0 ;;
24
+ *) err_t install.unknown_arg "$1"; aide >&2; exit 1 ;;
25
+ esac
26
+
27
+ claude="" opencode="" portee=projet
28
+ while [ $# -gt 0 ]; do
29
+ case "$1" in
30
+ --claude) claude=1 ;;
31
+ --opencode) opencode=1 ;;
32
+ --projet | --project) portee=projet ;;
33
+ --global) portee=global ;;
34
+ -h | --help) aide; exit 0 ;;
35
+ *) err_t install.unknown_arg "$1"; aide >&2; exit 1 ;;
36
+ esac
37
+ shift
38
+ done
39
+ [ -n "$claude$opencode" ] || claude=1 opencode=1
40
+
41
+ if [ "$portee" = projet ]; then
42
+ [ -n "$GIT_TOPLEVEL" ] || { err_t install.not_repo; exit 1; }
43
+ base="$GIT_TOPLEVEL"
44
+ fichier_claude="$base/.claude/settings.json"
45
+ fichier_opencode="$base/.opencode/plugins/repowarden-garde.js"
46
+ else
47
+ fichier_claude="$HOME/.claude/settings.json"
48
+ fichier_opencode="$HOME/.config/opencode/plugins/repowarden-garde.js"
49
+ fi
50
+
51
+ ecrits=()
52
+
53
+ # Hook PreToolUse de Claude Code : ajouté au settings.json (créé au besoin),
54
+ # rien si une commande « repowarden garde » y est déjà
55
+ init_claude() {
56
+ local f="$fichier_claude" entree tmp
57
+ has jq || { err_t agents.no_jq "$f"; return 1; }
58
+ entree="$(jq -n --arg m "$MATCHER_CLAUDE" --arg c "$COMMANDE_CLAUDE" \
59
+ '{matcher: $m, hooks: [{type: "command", command: $c}]}')"
60
+ if [ -f "$f" ]; then
61
+ jq -e . "$f" >/dev/null 2>&1 || { err_t agents.bad_json "Claude Code" "$f"; return 1; }
62
+ if jq -e '[.hooks.PreToolUse[]?.hooks[]?.command // empty | select(test("repowarden garde"))] | length > 0' "$f" >/dev/null; then
63
+ ok_t agents.present "Claude Code" "$f"
64
+ return 0
65
+ fi
66
+ tmp="$(mktemp)"
67
+ jq --argjson e "$entree" '.hooks.PreToolUse = ((.hooks.PreToolUse // []) + [$e])' "$f" >"$tmp"
68
+ cat "$tmp" >"$f"
69
+ rm -f "$tmp"
70
+ else
71
+ mkdir -p "$(dirname "$f")"
72
+ jq -n --argjson e "$entree" '{hooks: {PreToolUse: [$e]}}' >"$f"
73
+ fi
74
+ ecrits+=("$f")
75
+ ok_t agents.added "Claude Code" "$f"
76
+ }
77
+
78
+ # Plugin opencode : copie du modèle ; un fichier différent est gardé et signalé
79
+ init_opencode() {
80
+ local f="$fichier_opencode"
81
+ if [ -f "$f" ]; then
82
+ if cmp -s "$f" "$MODELE_OPENCODE"; then
83
+ ok_t agents.present opencode "$f"
84
+ else
85
+ attention_t agents.kept opencode "$f" "$MODELE_OPENCODE"
86
+ fi
87
+ return 0
88
+ fi
89
+ mkdir -p "$(dirname "$f")"
90
+ cp "$MODELE_OPENCODE" "$f"
91
+ ecrits+=("$f")
92
+ ok_t agents.added opencode "$f"
93
+ }
94
+
95
+ statut=0
96
+ [ -z "$claude" ] || init_claude || statut=1
97
+ [ -z "$opencode" ] || init_opencode || statut=1
98
+
99
+ has repowarden || attention_t agents.no_repowarden
100
+ if [ "$portee" = projet ] && [ ${#ecrits[@]} -gt 0 ]; then
101
+ info_t agents.versionner "${ecrits[*]#"$base/"}"
102
+ fi
103
+ exit "$statut"
package/bin/app CHANGED
@@ -23,7 +23,7 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
23
23
  # shellcheck source=../hooks/lib/common.sh
24
24
  source "$ROOT/hooks/lib/common.sh"
25
25
 
26
- aide() { sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; }
26
+ aide() { _tr help.app; printf '%b\n' "$_T" >&2; }
27
27
 
28
28
  commande="${1:-}"
29
29
  [ $# -eq 0 ] || shift
@@ -45,7 +45,7 @@ if [ "$commande" != init ]; then
45
45
  exit
46
46
  fi
47
47
 
48
- command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
48
+ gh_ready || exit 1
49
49
  command -v node >/dev/null || { err_t app.no_node; exit 1; }
50
50
  [ -n "$REPO" ] || REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
51
51
  owner="${REPO%%/*}"
package/bin/bot CHANGED
@@ -16,7 +16,7 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
16
16
  # shellcheck source=../hooks/lib/common.sh
17
17
  source "$ROOT/hooks/lib/common.sh"
18
18
 
19
- aide() { sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; }
19
+ aide() { _tr help.bot; printf '%b\n' "$_T" >&2; }
20
20
 
21
21
  # Scripts appelés (remplaçables dans les tests) et origine des clones
22
22
  BIN="${REPOWARDEN_BIN:-$ROOT/bin}"
package/bin/bots CHANGED
@@ -20,7 +20,7 @@ source "$ROOT/hooks/lib/common.sh"
20
20
  # shellcheck source=../hooks/lib/lang.sh
21
21
  source "$ROOT/hooks/lib/lang.sh"
22
22
 
23
- aide() { sed -n '2,13p' "$0" | sed 's/^# \{0,1\}//'; }
23
+ aide() { _tr help.bots; printf '%b\n' "$_T" >&2; }
24
24
 
25
25
  # Commandes enchaînées (remplaçables dans les tests)
26
26
  BIN="${REPOWARDEN_BIN:-$ROOT/bin}"
@@ -48,8 +48,8 @@ fi
48
48
  [ -n "$GIT_TOPLEVEL" ] || pas_maintenant bots.why_repo
49
49
  cd "$GIT_TOPLEVEL"
50
50
  [ "$FORGE" = github ] || pas_maintenant bots.why_github
51
- command -v gh >/dev/null || pas_maintenant bots.why_gh
52
- gh auth status >/dev/null 2>&1 || pas_maintenant bots.why_gh_login
51
+ gh_present || pas_maintenant bots.why_gh
52
+ gh_connected || pas_maintenant bots.why_gh_login
53
53
  REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || true)"
54
54
  [ -n "$REPO" ] || pas_maintenant bots.why_github
55
55
  [ "$(gh api "repos/$REPO" --jq .permissions.admin 2>/dev/null || true)" = true ] || pas_maintenant bots.why_admin
package/bin/code-mort CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env bash
2
- # Code mort introduit par ta branche, comme en CI : seules les lignes ajoutées ou
3
- # modifiées depuis la base comptent (commits, modifications en cours, nouveaux fichiers).
4
- # bin/code-mort [base] défaut : point de départ de la branche depuis origin/main
2
+ # Usage : repowarden code-mort [base]
3
+ #
4
+ # Code mort introduit par ta branche, comme en CI : seules les lignes ajoutées
5
+ # ou modifiées depuis la base comptent (commits, modifications en cours,
6
+ # nouveaux fichiers). Défaut : point de départ de la branche depuis origin/main.
5
7
  # Voir docs/code-mort.md : ce qui est prouvé (bloquant) et ce qui est candidat.
6
8
  set -euo pipefail
7
9
 
package/bin/commit CHANGED
@@ -1,19 +1,16 @@
1
1
  #!/usr/bin/env bash
2
- # Assistant de commit conventionnel : guide l'en-tête, le corps et le pied.
3
- # git cc [options de git commit] alias installé par install.sh
4
- # bin/commit --dry-run affiche le message sans commiter
5
- # git cc --strict une réponse refusée arrête tout (scripts :
6
- # sans cela, la ligne suivante serait lue
7
- # comme une nouvelle réponse)
8
- # git cc -m "description" [--type T] [--scope S] [--breaking NOTE]
9
- # [--body TEXTE] [--refs "Ticket : #12"]
10
- # sans question (scripts, agents) : mêmes
11
- # contrôles, toute réponse refusée arrête
12
- # tout ; type et scope déduits de la
13
- # branche s'ils sont omis
14
- # Les réponses sont lues sur l'entrée standard (terminal avec édition de
15
- # ligne, ou fichier/tube pour les tests). Le commit passe ensuite par les
16
- # hooks habituels. Couleurs désactivables : NO_COLOR=1.
2
+ # Usage : repowarden cc [options de git commit] (alias : git cc, installé par install.sh)
3
+ # repowarden cc -m "description" [--type T] [--scope S] [--breaking NOTE] [--body TEXTE] [--refs "Ticket : #12"]
4
+ # repowarden cc --dry-run
5
+ #
6
+ # Assistant de commit conventionnel : guide l'en-tête, le corps et le pied,
7
+ # puis commit via les hooks habituels. Sans question (-m : scripts, agents) :
8
+ # mêmes contrôles, type et scope déduits de la branche s'ils sont omis.
9
+ # --strict une réponse refusée arrête tout (rien n'est commité)
10
+ # --dry-run affiche le message sans commiter
11
+ # Les réponses sont lues sur l'entrée standard (terminal avec édition de ligne,
12
+ # ou fichier/tube pour les tests). Le commit passe ensuite par les hooks
13
+ # habituels. Couleurs désactivables : NO_COLOR=1.
17
14
  set -euo pipefail
18
15
 
19
16
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
package/bin/garde ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env bash
2
+ # Garde-fou des agents IA : reçoit sur l'entrée standard une action d'agent
3
+ # (JSON) et dit si elle est permise dans ce dépôt, avant qu'elle ne s'exécute.
4
+ # repowarden garde [--format claude|opencode]
5
+ # claude hook PreToolUse de Claude Code : tool_name, tool_input, cwd
6
+ # opencode plugin opencode (tool.execute.before) : tool, args, cwd (défaut)
7
+ # Code 0 : permis. Code 2 : refusé, raison et commande à lancer sur la sortie
8
+ # d'erreur (Claude Code bloque l'appel et transmet le message à l'agent ; le
9
+ # plugin opencode lève une erreur). Tout autre code (jq absent, JSON illisible)
10
+ # n'empêche rien : une panne du garde-fou ne bloque jamais un agent.
11
+ # Seulement dans un dépôt repowarden ; ailleurs tout est permis. Mêmes réglages
12
+ # que les hooks (protectedBranches, integrationBranch, suivi des tickets).
13
+ set -uo pipefail
14
+
15
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
16
+ # shellcheck source=../hooks/lib/common.sh
17
+ source "$ROOT/hooks/lib/common.sh"
18
+ # shellcheck source=../hooks/lib/tickets.sh
19
+ source "$ROOT/hooks/lib/tickets.sh"
20
+
21
+ aide() { _tr help.garde; printf '%b\n' "$_T"; }
22
+
23
+ format=opencode
24
+ while [ $# -gt 0 ]; do
25
+ case "$1" in
26
+ -h | --help) aide; exit 0 ;;
27
+ --format) shift; format="${1:-}" ;;
28
+ --format=*) format="${1#--format=}" ;;
29
+ *) err_t install.unknown_arg "$1"; aide >&2; exit 1 ;;
30
+ esac
31
+ shift
32
+ done
33
+ case "$format" in claude | opencode) ;; *) err_t garde.format "$format"; exit 1 ;; esac
34
+
35
+ has jq || { attention_t garde.no_jq; exit 1; }
36
+ entree="$(cat)"
37
+ if [ "$format" = claude ]; then o=tool_name a=tool_input; else o=tool a=args; fi
38
+ outil="$(jq -r ".$o // \"\"" <<<"$entree" 2>/dev/null)" || { attention_t garde.json; exit 1; }
39
+ cwd="$(jq -r '.cwd // ""' <<<"$entree")"
40
+ args="$(jq -c ".$a // {}" <<<"$entree")"
41
+ [ -n "$cwd" ] && [ -d "$cwd" ] || cwd="$PWD"
42
+
43
+ # Refus : raison et commande à lancer, puis code 2
44
+ refuser() {
45
+ _tr "$@"
46
+ printf '✖ repowarden : %b\n' "$_T" >&2
47
+ exit 2
48
+ }
49
+
50
+ # REPLY = dossier existant le plus proche du chemin $1 (absolu, ou relatif à $cwd)
51
+ dossier_r() {
52
+ local p="$1"
53
+ case "$p" in /*) ;; *) p="$cwd/$p" ;; esac
54
+ while [ ! -d "$p" ] && [ "$p" != / ] && [ -n "$p" ]; do p="$(dirname "$p")"; done
55
+ REPLY="$p"
56
+ }
57
+
58
+ # Vrai si le dossier courant est dans un dépôt repowarden : .repowarden.conf,
59
+ # réglage repowarden.*, ou hooks repowarden actifs. Charge sa configuration.
60
+ depot_repowarden() {
61
+ local hp
62
+ git rev-parse --show-toplevel >/dev/null 2>&1 || return 1
63
+ cfg_load
64
+ i18n_init
65
+ # shellcheck disable=SC2034 # cache de tickets_managed (tickets.sh), propre à ce dépôt
66
+ TICKETS_MANAGED=""
67
+ [ -n "$CFG_FILE$CFG_GIT" ] && return 0
68
+ hp="$(git config --get core.hooksPath 2>/dev/null || true)"
69
+ [ -n "$hp" ] && [ -f "$hp/lib/tickets.sh" ] && [ -f "$hp/lib/common.sh" ]
70
+ }
71
+
72
+ # Branche protégée : protectedBranches (défaut main master) ou branche d'intégration
73
+ protegee() {
74
+ cfg_r protectedBranches "main master"
75
+ [[ " $REPLY " == *" $1 "* ]] && return 0
76
+ cfg_r integrationBranch ""
77
+ [ -n "$REPLY" ] && [ "$REPLY" = "$1" ]
78
+ }
79
+
80
+ # Modification du fichier $1 : seulement sur une branche de travail (de ticket,
81
+ # si le dépôt suit ses tickets)
82
+ verifier_fichier() {
83
+ dossier_r "$1"
84
+ local d="$REPLY"
85
+ (
86
+ cd "$d" 2>/dev/null || exit 0
87
+ depot_repowarden || exit 0
88
+ # Fichiers internes de git (.git/…) : hors du travail de l'agent
89
+ case "$(pwd -P)/" in "$(cd "$(git rev-parse --git-dir)" && pwd -P)"/*) exit 0 ;; esac
90
+ branche="$(git symbolic-ref -q --short HEAD 2>/dev/null || true)"
91
+ [ -n "$branche" ] || refuser garde.detache "$GIT_TOPLEVEL"
92
+ if protegee "$branche"; then
93
+ tickets_managed && refuser garde.protegee "$branche"
94
+ refuser garde.protegee_libre "$branche"
95
+ fi
96
+ if tickets_managed; then
97
+ branch_ticket_r "$branche"
98
+ [ -n "$REPLY" ] || refuser garde.hors_ticket "$branche"
99
+ fi
100
+ exit 0
101
+ ) || exit $?
102
+ }
103
+
104
+ # Commande git (mots $@, sans « git ») lancée depuis le dossier $dir
105
+ verifier_git() {
106
+ local mot sous="" args_git=() repertoire="$dir"
107
+ # Options globales : -C <dossier> (cumulées), -c <clé=valeur>, autres
108
+ while [ $# -gt 0 ]; do
109
+ case "$1" in
110
+ -C) shift; case "${1:-}" in /*) repertoire="$1" ;; *) repertoire="$repertoire/${1:-}" ;; esac ;;
111
+ -c) shift ;;
112
+ -*) ;;
113
+ *) sous="$1"; shift; break ;;
114
+ esac
115
+ shift
116
+ done
117
+ [ -n "$sous" ] || return 0
118
+ args_git=("$@")
119
+ dossier_r "$repertoire"
120
+ repertoire="$REPLY"
121
+ (
122
+ cd "$repertoire" 2>/dev/null || exit 0
123
+ depot_repowarden || exit 0
124
+ ligne="git $sous${args_git[*]+ ${args_git[*]}}"
125
+ for mot in ${args_git[@]+"${args_git[@]}"}; do
126
+ [ "$mot" != --no-verify ] || refuser garde.no_verify "$ligne"
127
+ done
128
+ case "$sous" in
129
+ commit)
130
+ amend="" noedit=""
131
+ for mot in ${args_git[@]+"${args_git[@]}"}; do
132
+ case "$mot" in
133
+ --amend) amend=1 ;;
134
+ --no-edit) noedit=1 ;;
135
+ # Options courtes groupées : -n est --no-verify (-nm, -an…)
136
+ -[!-]*) [[ "$mot" != *n* ]] || refuser garde.no_verify "$ligne" ;;
137
+ esac
138
+ done
139
+ [ -n "$amend" ] && [ -n "$noedit" ] && exit 0
140
+ refuser garde.commit "$ligne"
141
+ ;;
142
+ add)
143
+ for mot in ${args_git[@]+"${args_git[@]}"}; do
144
+ case "$mot" in
145
+ . | ./ | --all | :/) refuser garde.add_tout "$ligne" ;;
146
+ -[!-]*) [[ "$mot" != *A* ]] || refuser garde.add_tout "$ligne" ;;
147
+ esac
148
+ done
149
+ ;;
150
+ checkout | switch | branch | worktree)
151
+ tickets_managed || exit 0
152
+ cree=""
153
+ case "$sous" in
154
+ checkout) for mot in ${args_git[@]+"${args_git[@]}"}; do case "$mot" in -b | -B | --orphan) cree=1 ;; esac; done ;;
155
+ switch) for mot in ${args_git[@]+"${args_git[@]}"}; do case "$mot" in -c | -C | --create | --force-create | --orphan | --create=* | --force-create=*) cree=1 ;; esac; done ;;
156
+ worktree)
157
+ [ "${args_git[0]:-}" = add ] || exit 0
158
+ for mot in ${args_git[@]+"${args_git[@]}"}; do case "$mot" in -b | -B) cree=1 ;; esac; done
159
+ ;;
160
+ branch)
161
+ nom=""
162
+ for mot in ${args_git[@]+"${args_git[@]}"}; do
163
+ case "$mot" in
164
+ -d | -D | --delete | -m | -M | --move | -c | -C | --copy | -l | --list | -a | --all | -r | --remotes | \
165
+ -v | -vv | --verbose | --show-current | --contains | --no-contains | --merged | --no-merged | \
166
+ -u | --set-upstream-to | --set-upstream-to=* | --unset-upstream | --edit-description | --points-at) exit 0 ;;
167
+ -*) ;;
168
+ *) nom="$mot" ;;
169
+ esac
170
+ done
171
+ [ -z "$nom" ] || cree=1
172
+ ;;
173
+ esac
174
+ [ -z "$cree" ] || refuser garde.branche "$ligne"
175
+ ;;
176
+ esac
177
+ exit 0
178
+ ) || exit $?
179
+ }
180
+
181
+ # Ligne de commande shell : chaque commande (&&, ||, ;, |, retour à la ligne),
182
+ # « cd » suivi, variables d'environnement en tête ignorées
183
+ verifier_shell() {
184
+ local commande="$1" segment mots m nl=$'\n' lignes
185
+ dir="$cwd"
186
+ # Une commande par ligne. Découpage hors de <( … ) : bash 3.2 (macOS) y
187
+ # lit mal ces motifs (« bad substitution ») et ne vérifierait plus rien
188
+ lignes="${commande//&&/$nl}"
189
+ lignes="${lignes//||/$nl}"
190
+ lignes="${lignes//;/$nl}"
191
+ lignes="${lignes//|/$nl}"
192
+ lignes="${lignes//&/$nl}"
193
+ while IFS= read -r segment; do
194
+ # shellcheck disable=SC2162 # les antislashs restent tels quels, comme dans la commande
195
+ read -a mots <<<"$segment" || true
196
+ set -- ${mots[@]+"${mots[@]}"}
197
+ while [ $# -gt 0 ]; do
198
+ case "$1" in
199
+ [A-Za-z_]*=* | '(' | '{' | '!' | command | exec | env | sudo | time | nohup) shift ;;
200
+ *) break ;;
201
+ esac
202
+ done
203
+ [ $# -gt 0 ] || continue
204
+ m="${1//[\"\']/}"
205
+ case "$m" in
206
+ cd)
207
+ case "${2:-}" in
208
+ "" | \~) dir="$HOME" ;;
209
+ /*) dir="${2//[\"\']/}" ;;
210
+ \~/*) dir="$HOME/${2#\~/}" ;;
211
+ *) dir="$dir/${2//[\"\']/}" ;;
212
+ esac
213
+ ;;
214
+ git | */git)
215
+ shift
216
+ verifier_git "${@//[\"\']/}"
217
+ ;;
218
+ esac
219
+ done <<<"$lignes"
220
+ }
221
+
222
+ case "$outil" in
223
+ Edit | Write | MultiEdit | NotebookEdit | edit | write | multiedit)
224
+ chemin="$(jq -r '.file_path // .filePath // .notebook_path // empty' <<<"$args" 2>/dev/null)"
225
+ [ -z "$chemin" ] || verifier_fichier "$chemin"
226
+ ;;
227
+ apply_patch)
228
+ while IFS= read -r chemin; do
229
+ [ -z "$chemin" ] || verifier_fichier "$chemin"
230
+ done < <(jq -r '.patchText // empty' <<<"$args" 2>/dev/null |
231
+ sed -nE -e 's/^\*\*\* (Add|Update|Delete) File: //p' -e 's/^\*\*\* Move to: //p')
232
+ ;;
233
+ Bash | bash)
234
+ verifier_shell "$(jq -r '.command // empty' <<<"$args" 2>/dev/null)"
235
+ ;;
236
+ esac
237
+ exit 0
package/bin/migrer CHANGED
@@ -14,7 +14,7 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
14
14
  # shellcheck source=../hooks/lib/common.sh
15
15
  source "$ROOT/hooks/lib/common.sh"
16
16
 
17
- aide() { sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; }
17
+ aide() { _tr help.migrer; printf '%b\n' "$_T" >&2; }
18
18
 
19
19
  PR="" HOOKS_LEFTHOOK=""
20
20
  while [ $# -gt 0 ]; do
@@ -35,6 +35,8 @@ majeure_r() {
35
35
  local v
36
36
  repowarden_version_r "$ROOT"
37
37
  v="$REPLY"
38
+ # 0.0.0-dev : version inconnue (clone sans tags), rien à déduire
39
+ if [ "$v" = 0.0.0-dev ]; then REPLY=""; return; fi
38
40
  REPLY="${v%%.*}"
39
41
  REPLY="${REPLY%%-*}"
40
42
  [[ "$v" != *.0.0-* ]] || REPLY=$((REPLY - 1))
@@ -45,6 +47,7 @@ else
45
47
  majeure_r
46
48
  MAJEURE="$REPLY"
47
49
  fi
50
+ [ -n "$MAJEURE" ] || { err_t mig.unknown_version "$ROOT"; exit 1; }
48
51
  [[ "$MAJEURE" =~ ^[1-9][0-9]*$ ]] || { err_t mig.no_major "$MAJEURE"; exit 1; }
49
52
  BRANCHE="chore/migration-repowarden-v$MAJEURE"
50
53
 
@@ -31,7 +31,7 @@ while [ $# -gt 0 ]; do
31
31
  --workflow) shift; WORKFLOW="${1:?--workflow attend un fichier}" ;;
32
32
  --environnement | --environment) shift; ENVIRONMENT="${1:?--environnement attend un nom}" ;;
33
33
  --dry-run) DRY_RUN=true ;;
34
- -h | --help) sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
34
+ -h | --help) _tr help.npm-publication; printf '%b\n' "$_T"; exit 0 ;;
35
35
  *) err_t install.unknown_arg "$1"; exit 1 ;;
36
36
  esac
37
37
  shift
package/bin/pr-checks CHANGED
@@ -10,14 +10,8 @@ source "$ROOT/hooks/lib/common.sh"
10
10
  source "$ROOT/hooks/lib/i18n.sh"
11
11
 
12
12
  aide() {
13
- cat <<EOF
14
- Usage: repowarden pr checks <n>
15
-
16
- Affiche l'état des checks de la PR #<n>.
17
-
18
- Exemple:
19
- repowarden pr checks 123
20
- EOF
13
+ _tr help.pr
14
+ printf '%b\n' "$_T"
21
15
  }
22
16
 
23
17
  [ $# -eq 1 ] || { aide >&2; exit 1; }
package/bin/pr-label CHANGED
@@ -10,20 +10,14 @@ source "$ROOT/hooks/lib/common.sh"
10
10
  source "$ROOT/hooks/lib/i18n.sh"
11
11
 
12
12
  aide() {
13
- cat <<EOF
14
- Usage: repowarden pr label <n> <label> [--remove]
15
-
16
- Ajoute ou retire un label sur la PR #<n>.
17
-
18
- Options:
19
- --remove Retire le label au lieu de l'ajouter
20
-
21
- Exemples:
22
- repowarden pr label 123 "ready-for-review"
23
- repowarden pr label 123 "needs-changes" --remove
24
- EOF
13
+ _tr help.pr
14
+ printf '%b\n' "$_T"
25
15
  }
26
16
 
17
+ case "${1:-}" in
18
+ -h | --help) aide; exit 0 ;;
19
+ esac
20
+
27
21
  [ $# -ge 2 ] || { aide >&2; exit 1; }
28
22
  command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
29
23
 
package/bin/proteger CHANGED
@@ -56,7 +56,7 @@ while [ $# -gt 0 ]; do
56
56
  --sans-tags) NO_TAGS=1 ;;
57
57
  --dry-run) DRY_RUN=1 ;;
58
58
  --verifier) VERIFY=1 ;;
59
- -h | --help) sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
59
+ -h | --help) _tr help.proteger; printf '%b\n' "$_T"; exit 0 ;;
60
60
  *) err_t install.unknown_arg "$1"; exit 1 ;;
61
61
  esac
62
62
  shift