@roomi-fields/grillhouse 0.23.0 → 0.24.0
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/.claude-plugin/plugin.json +1 -1
- package/METACADRE.md +1 -1
- package/agents/explorateur.md +4 -2
- package/agents/questionneur.md +1 -1
- package/bin/grillhouse.mjs +3 -58
- package/cadre/templates/projet/CLAUDE.md +5 -1
- package/cadre/templates/projet/docs/agents/issue-tracker.md +4 -4
- package/charte.md +23 -6
- package/docs/ARCHITECTURE.md +127 -1
- package/hooks/register.tsx +3 -13
- package/package.json +13 -1
- package/scripts/bilan.mjs +134 -88
- package/scripts/circuit.mjs +1547 -2248
- package/scripts/composants-affectes.mjs +27 -108
- package/scripts/consommateurs-arbitres.mjs +15 -21
- package/scripts/consommateurs.d.ts +8 -0
- package/scripts/consommateurs.mjs +5 -1
- package/scripts/dette.d.ts +23 -0
- package/scripts/dette.mjs +76 -13
- package/scripts/droits.mjs +38 -44
- package/scripts/elements-du-lot.mjs +246 -0
- package/scripts/enveloppe/enveloppe.mjs +105 -232
- package/scripts/enveloppe/lancer.sh +79 -49
- package/scripts/enveloppe/paquets-du-plan.mjs +49 -0
- package/scripts/etapes.mjs +148 -213
- package/scripts/gardes-du-cadre.mjs +8 -6
- package/scripts/grillhouse-maj.mjs +31 -9
- package/scripts/index-interfaces.mjs +21 -1
- package/scripts/integration/integrer.mjs +2 -2
- package/scripts/interfaces-contre-code.mjs +25 -17
- package/scripts/migrations/0.23.0-config-vitest.mjs +26 -23
- package/scripts/migrations/0.23.2-copies-du-cadre.mjs +201 -0
- package/scripts/migrations/0.24.0-circuit-simplifie.mjs +231 -0
- package/scripts/migrations.mjs +41 -6
- package/scripts/paquets.d.ts +5 -0
- package/scripts/paquets.mjs +3 -0
- package/scripts/references-par-les-types.mjs +55 -36
- package/scripts/registre.mjs +7 -15
- package/scripts/resultats.mjs +283 -142
- package/scripts/resumes.mjs +1 -1
- package/scripts/session-start.sh +1 -2
- package/scripts/sortie.mjs +1 -1
- package/scripts/sources.mjs +28 -0
- package/scripts/sous-commandes.mjs +62 -0
- package/scripts/tableau.mjs +85 -191
- package/scripts/tests.mjs +19 -17
- package/scripts/verifier.mjs +5 -4
- package/scripts/verrou-de-machine.mjs +131 -24
- package/scripts/verrous/verrou.mjs +66 -5
- package/skills/developpeur/SKILL.md +60 -50
- package/skills/explorateur/SKILL.md +90 -64
- package/skills/grill/SKILL.md +1 -1
- package/skills/mesure/SKILL.md +2 -1
- package/skills/pitmaster/SKILL.md +132 -118
- package/skills/pitmaster/references/consigne-agent.md +54 -148
- package/skills/questionneur/SKILL.md +18 -18
- package/skills/relecteur/SKILL.md +69 -23
- package/skills/testwriter/SKILL.md +46 -35
- package/types/index.d.ts +1 -3
- package/agents/referent-technique.md +0 -9
- package/agents/regulateur.md +0 -11
- package/scripts/enveloppe/composant.mjs +0 -11
- package/scripts/etat-du-circuit.mjs +0 -104
- package/skills/referent-technique/SKILL.md +0 -145
- package/skills/regulateur/SKILL.md +0 -220
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Launches a role agent on one ticket, as its own Claude session inside the envelope of its
|
|
3
|
-
#
|
|
3
|
+
# plan, the packages it writes (one session of the testwriter or the developpeur for the whole
|
|
4
|
+
# ticket, `.` as its component and the plan as `--paquets`, grillhouse-3uv.95.6). The supervisor runs it in the background and is told when the session ends.
|
|
4
5
|
#
|
|
5
|
-
# npx grillhouse lancer [--modele <m>] [--effort <e>] [--seance <id> | --reprise <id>] <ticket> <rôle> <composant> <fichier de consigne>
|
|
6
|
+
# npx grillhouse lancer [--modele <m>] [--effort <e>] [--seance <id> | --reprise <id>] [--paquets <liste>] <ticket> <rôle> <composant> <fichier de consigne>
|
|
6
7
|
#
|
|
7
8
|
# - <composant> is the component's path from the root (`packages/<nom>`, or `.` for the whole
|
|
8
9
|
# repository). It is judged before the copy is prepared, by the envelope's rule
|
|
@@ -10,6 +11,11 @@
|
|
|
10
11
|
# when it exists, else in the main tree or in the tree of the branch agent/<ticket> when it
|
|
11
12
|
# exists (`git cat-file -e`; `.` is always admitted): a path that names nothing there is refused on the standard error, CODE_USAGE, nothing prepared; when
|
|
12
13
|
# it is the name of a package or of its folder, the refusal names the path it means.
|
|
14
|
+
# - --paquets <liste> is the plan of the session: the paths of the packages it writes, in the form
|
|
15
|
+
# of the envelope's variable (`ecrireLaListe` of paquets-du-plan.mjs, `packages/a:packages/b`),
|
|
16
|
+
# each judged as <composant> is; without it, the plan is <composant> alone. The envelope shows
|
|
17
|
+
# the session the whole copy and opens in writing the packages of the plan alone. It takes a
|
|
18
|
+
# value as --modele does.
|
|
13
19
|
# - --modele <m> and --effort <e> override, for this session only, the model and the thinking level
|
|
14
20
|
# of the role's definition (its agent in the frame's plugin, agents/<rôle>.md); they reach claude
|
|
15
21
|
# as --model and --effort.
|
|
@@ -45,21 +51,22 @@
|
|
|
45
51
|
# dependencies are installed when `node_modules` is absent or `package-lock.json` is newer than
|
|
46
52
|
# the last installation (`node_modules/.package-lock.json`, written by npm), and it is built there
|
|
47
53
|
# by Turborepo, which restores an unchanged build from its cache, outside the envelope, so the
|
|
48
|
-
# agent finds the
|
|
49
|
-
# before the target: for a
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
# and
|
|
54
|
+
# agent finds the builds of the packages out of its plan. As Bazel builds the dependencies of a
|
|
55
|
+
# target before the target: for a plan whose every path is a package of the frame (the circuit's
|
|
56
|
+
# session over the whole ticket, `.` as its component and the plan as `--paquets`, or a component
|
|
57
|
+
# alone), their providers are built first (the packages whose build their builds wait for, read
|
|
58
|
+
# in Turborepo's graph, `turbo run build --filter=<paquet>… --dry=json`, which node reads on its
|
|
59
|
+
# standard input, whatever its size), and a failure stops the launch, CODE_COPIE;
|
|
60
|
+
# then the traces of other packages their tests wait for (`grillhouse.traces`, read in Turborepo's
|
|
61
|
+
# plan of their tests, `turbo run test:vitest --filter=<paquet>… --dry=json`), which the envelope
|
|
62
|
+
# shows read-only, and a failure stops the launch, CODE_COPIE; then the packages, their own
|
|
63
|
+
# traces and what their tests read (`turbo run build <their traces> --filter=<paquet>...…
|
|
57
64
|
# --continue=dependencies-successful`), whose failure does not stop it: each task whose
|
|
58
|
-
# dependencies succeed goes to its end, so what
|
|
59
|
-
# whole; the session opens, its instruction ending with a section « La construction de ton
|
|
65
|
+
# dependencies succeed goes to its end, so what their tests read without depending on them is
|
|
66
|
+
# built whole; the session opens, its instruction ending with a section « La construction de ton
|
|
60
67
|
# paquet échoue » with the end of that output, since repairing it is the session's work (a
|
|
61
|
-
# provider's lot that breaks its consumers).
|
|
62
|
-
#
|
|
68
|
+
# provider's lot that breaks its consumers). Their consumers are not built. Any other plan, the
|
|
69
|
+
# whole repository (`.`) included, builds the copy whole (`turbo run build`). The
|
|
63
70
|
# installation and the build play through `scripts/sous-modules.sh monter`, each shared submodule
|
|
64
71
|
# of the main repository read-only, by the list the pose printed, whatever the installation
|
|
65
72
|
# rewrites afterwards; with a shared submodule and no possible mount (bwrap absent or
|
|
@@ -69,11 +76,13 @@
|
|
|
69
76
|
# - The session runs `claude -p` with the role's agent and, as its prompt, read on its standard
|
|
70
77
|
# input from a temporary file the launcher writes and removes (an argument may not pass the
|
|
71
78
|
# 128 KiB Linux allows one, MAX_ARG_STRLEN), the instruction file
|
|
72
|
-
# followed by the section « Ce que les composants d'avant publient
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
# elements
|
|
76
|
-
#
|
|
79
|
+
# followed by the section « Ce que les composants d'avant publient », for each package of the
|
|
80
|
+
# plan (one part per package when the plan holds several, grillhouse-3uv.95.6): for each
|
|
81
|
+
# component whose `## Consommateurs` section names the package, its line, the names of the
|
|
82
|
+
# elements declared for the package, and the address of the rubric « Rend » of its frame, the
|
|
83
|
+
# rest of its elements left to the index of the interfaces (`scripts/index-interfaces.mjs
|
|
84
|
+
# --publie <plan>`, read in the prepared copy; a reading that fails stops the launch,
|
|
85
|
+
# CODE_COPIE), then the
|
|
77
86
|
# section « Ton dossier de travail », which names the session's working directory, where every
|
|
78
87
|
# temporary file goes (`dossierDeTravail` of enveloppe.mjs, the envelope's TMPDIR), then the
|
|
79
88
|
# section « La construction de ton paquet échoue » when it fails. The prompt
|
|
@@ -83,7 +92,7 @@
|
|
|
83
92
|
# the launch, CODE_COPIE): the user's own configuration left out, its settings on the command
|
|
84
93
|
# line (its refusals, among them the change of its author at the ticket, AUTEUR_FIXE: its
|
|
85
94
|
# comments carry the author the launch names in BEADS_ACTOR, which the envelope passes on; its
|
|
86
|
-
# locks), its tools and
|
|
95
|
+
# locks), its tools and the servers of the index, for the reading of the whole copy.
|
|
87
96
|
# - A role that ends on a sheet (scripts/resultats.mjs: the testwriter, the developpeur) runs with
|
|
88
97
|
# `--output-format json --json-schema <its schema>` (`npx grillhouse resultats --schema
|
|
89
98
|
# <rôle>`): claude's JSON result, its sheet in `structured_output`, goes to
|
|
@@ -96,19 +105,22 @@
|
|
|
96
105
|
# launcher writes the session's exit code to .claude/worktrees/<ticket>.fin, which a launch
|
|
97
106
|
# removes first: a launch that stops before its session leaves none, so the circuit
|
|
98
107
|
# (scripts/circuit.mjs) tells a code of the session from CODE_USAGE, CODE_REFUS and CODE_COPIE.
|
|
99
|
-
#
|
|
100
|
-
#
|
|
108
|
+
# A session its lock stopped on a write out of the plan (scripts/verrous/verrou.mjs) left the
|
|
109
|
+
# reason in its working directory (`hors-plan`, removed before the session): the launcher moves
|
|
110
|
+
# it to .claude/worktrees/<ticket>.hors-plan, which a launch removes first and the circuit reads,
|
|
111
|
+
# and adds it to the log. It then writes the session's line to the register
|
|
112
|
+
# (scripts/registre.mjs --copie), and exits with the envelope's code.
|
|
101
113
|
# - The exit codes are named in scripts/enveloppe/codes.mjs; a malformed call exits CODE_USAGE.
|
|
102
114
|
# - CLAUDE_BIN replaces `claude` (the tests use it).
|
|
103
115
|
set -euo pipefail
|
|
104
116
|
ici="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
105
117
|
eval "$(node "$ici/codes.mjs")"
|
|
106
|
-
usage="usage: npx grillhouse lancer [--modele <m>] [--effort <e>] [--seance <id> | --reprise <id>] <ticket> <rôle> <composant> <fichier de consigne>"
|
|
118
|
+
usage="usage: npx grillhouse lancer [--modele <m>] [--effort <e>] [--seance <id> | --reprise <id>] [--paquets <liste>] <ticket> <rôle> <composant> <fichier de consigne>"
|
|
107
119
|
refus_usage() { echo "$usage" >&2; exit "$CODE_USAGE"; }
|
|
108
|
-
modele="" effort="" seance="" reprise="" surcharge=()
|
|
120
|
+
modele="" effort="" seance="" reprise="" liste="" surcharge=()
|
|
109
121
|
while [ $# -gt 0 ]; do
|
|
110
122
|
case "$1" in
|
|
111
|
-
--modele|--effort|--seance|--reprise)
|
|
123
|
+
--modele|--effort|--seance|--reprise|--paquets)
|
|
112
124
|
[ $# -ge 2 ] && [ -n "$2" ] && [[ "$2" != --* ]] || refus_usage
|
|
113
125
|
if [ "$1" = --modele ]; then
|
|
114
126
|
modele=$2
|
|
@@ -116,6 +128,8 @@ while [ $# -gt 0 ]; do
|
|
|
116
128
|
seance=$2
|
|
117
129
|
elif [ "$1" = --reprise ]; then
|
|
118
130
|
reprise=$2
|
|
131
|
+
elif [ "$1" = --paquets ]; then
|
|
132
|
+
liste=$2
|
|
119
133
|
else
|
|
120
134
|
case "$2" in low|medium|high|xhigh|max) effort=$2 ;; *) refus_usage ;; esac
|
|
121
135
|
fi
|
|
@@ -131,6 +145,8 @@ done
|
|
|
131
145
|
[ -z "$reprise" ] || surcharge+=(--resume "$reprise")
|
|
132
146
|
[ $# -eq 4 ] || refus_usage
|
|
133
147
|
ticket=$1 role=$2 composant=$3 consigne=$4
|
|
148
|
+
# The plan of the session: the packages it writes.
|
|
149
|
+
paquets=${liste:-$composant}
|
|
134
150
|
# The main tree, from the common git directory: launched from an agent copy, the new copy still
|
|
135
151
|
# lands next to the others, never inside one.
|
|
136
152
|
racine=$(cd "$(git rev-parse --path-format=absolute --git-common-dir)/.." && pwd)
|
|
@@ -147,7 +163,7 @@ if [ -d "$racine/.claude/worktrees/$ticket" ]; then
|
|
|
147
163
|
elif git -C "$racine" rev-parse --verify --quiet "refs/heads/agent/$ticket" > /dev/null; then
|
|
148
164
|
branche="agent/$ticket"
|
|
149
165
|
fi
|
|
150
|
-
refus_composant=$(node --input-type=module -e "import { spawnSync } from 'node:child_process'; import { existsSync } from 'node:fs'; import path from 'node:path'; import { jugerComposant } from '$ici/enveloppe.mjs'; import { paquets } from '$ici/../paquets.mjs'; const [depot, composant, branche] = process.argv.slice(1); const dansBranche = p => { const rel = path.relative(depot, p); return rel === '' || (!rel.startsWith('..') && spawnSync('git', ['-C', depot, 'cat-file', '-e', branche + ':' + rel]).status === 0); }; const existe = p => existsSync(p) || (branche !== '' && dansBranche(p)); process.stdout.write(jugerComposant({ depot, composant, paquets:
|
|
166
|
+
refus_composant=$(node --input-type=module -e "import { spawnSync } from 'node:child_process'; import { existsSync } from 'node:fs'; import path from 'node:path'; import { jugerComposant } from '$ici/enveloppe.mjs'; import { lireLaListe } from '$ici/paquets-du-plan.mjs'; import { paquets } from '$ici/../paquets.mjs'; const [depot, composant, liste, branche] = process.argv.slice(1); const dansBranche = p => { const rel = path.relative(depot, p); return rel === '' || (!rel.startsWith('..') && spawnSync('git', ['-C', depot, 'cat-file', '-e', branche + ':' + rel]).status === 0); }; const existe = p => existsSync(p) || (branche !== '' && dansBranche(p)); const tous = paquets(depot); process.stdout.write([composant, ...lireLaListe(liste)].map(c => jugerComposant({ depot, composant: c, paquets: tous }, { existe })).find(Boolean) ?? '');" "$juge" "$composant" "$paquets" "$branche") || exit "$CODE_USAGE"
|
|
151
167
|
[ -z "$refus_composant" ] || { echo "⛔ $refus_composant" >&2; exit "$CODE_USAGE"; }
|
|
152
168
|
# The ticket is matched whole: `demo-3160` is not `demo-316`, and its dots are dots.
|
|
153
169
|
motif=$(printf '%s' "$ticket" | sed 's/[.[\*^$]/\\&/g')
|
|
@@ -157,8 +173,9 @@ copie="$racine/.claude/worktrees/$ticket"
|
|
|
157
173
|
journal="$copie.log"
|
|
158
174
|
fin="$copie.fin"
|
|
159
175
|
resultat="$copie.resultat.json"
|
|
176
|
+
hors_plan="$copie.hors-plan"
|
|
160
177
|
mkdir -p "$(dirname "$copie")"
|
|
161
|
-
rm -f "$fin" "$resultat"
|
|
178
|
+
rm -f "$fin" "$resultat" "$hors_plan"
|
|
162
179
|
printf '=== %s · %s · %s ===\n' "$(date -Iseconds)" "$role" "$composant" >> "$journal"
|
|
163
180
|
# A branch still in the queue is not relaunched: the queue brings it onto main, or sends it back.
|
|
164
181
|
if node --input-type=module -e "import { lireEntrees } from '$ici/../integration/file-attente.mjs'; const [r, b, t] = process.argv.slice(1); process.exit(lireEntrees(r).some(e => e.branche === b || e.ticket === t) ? 0 : 1);" "$racine" "agent/$ticket" "$ticket"; then
|
|
@@ -217,24 +234,28 @@ echec=$(mktemp)
|
|
|
217
234
|
if [ ! -d "$copie/node_modules" ] || [ "$copie/package-lock.json" -nt "$installe" ]; then
|
|
218
235
|
monter npm --prefix "$copie" install --no-save --no-audit --no-fund --silent || exit 1
|
|
219
236
|
fi
|
|
220
|
-
# The
|
|
221
|
-
|
|
222
|
-
|
|
237
|
+
# The packages of the session's plan that are packages of the frame: their names, one per
|
|
238
|
+
# line; none when a path of the plan is no package of the frame (the root, `.`, a folder).
|
|
239
|
+
noms=$(node --input-type=module -e "import path from 'node:path'; import { lireLaListe } from '$ici/paquets-du-plan.mjs'; import { paquets } from '$ici/../paquets.mjs'; const [r, liste] = process.argv.slice(1); const tous = paquets(r).filter(p => !p.hors); const l = lireLaListe(liste).map(d => tous.find(p => p.dossier === path.normalize(d).replace(/\/\$/, ''))?.pkg.name ?? null); process.stdout.write(l.length && l.every(Boolean) ? l.join('\n') : '');" "$copie" "$paquets") || exit 1
|
|
240
|
+
if [ -z "$noms" ]; then
|
|
223
241
|
(cd "$copie" && monter npx --no-install turbo run build) || exit 1
|
|
224
242
|
else
|
|
225
|
-
|
|
226
|
-
|
|
243
|
+
mapfile -t lesNoms <<<"$noms"
|
|
244
|
+
cibles=() lecteurs=()
|
|
245
|
+
for n in "${lesNoms[@]}"; do cibles+=("--filter=$n"); lecteurs+=("--filter=$n..."); done
|
|
246
|
+
# Their providers: the packages whose build their own builds wait for, as Turborepo reads them.
|
|
247
|
+
graphe=$(cd "$copie" && monter npx --no-install turbo run build "${cibles[@]}" --dry=json) || exit 1
|
|
227
248
|
# The graph comes on the standard input: as an argument, it may pass the size Linux allows one.
|
|
228
|
-
fournisseurs=$(node -e 'const
|
|
249
|
+
fournisseurs=$(node -e 'const plan = process.argv.slice(1); const t = JSON.parse(require("node:fs").readFileSync(0, "utf8")).tasks.filter(t => !plan.includes(t.package)); console.log([...new Set(t.map(t => `--filter=${t.package}`))].join("\n"));' "${lesNoms[@]}" <<<"$graphe") || exit 1
|
|
229
250
|
if [ -n "$fournisseurs" ]; then
|
|
230
251
|
mapfile -t filtres <<<"$fournisseurs"
|
|
231
252
|
(cd "$copie" && monter npx --no-install turbo run build "${filtres[@]}") || exit 1
|
|
232
253
|
fi
|
|
233
|
-
# The traces
|
|
234
|
-
# package's trace is produced here, and a failure stops the launch, as a provider's;
|
|
235
|
-
# waits for its
|
|
236
|
-
plan=$(cd "$copie" && monter npx --no-install turbo run test:vitest "
|
|
237
|
-
traces() { node --input-type=module -e "import { readFileSync } from 'node:fs'; import { tracesDuPlan } from '$ici/../turbo-des-paquets.mjs'; const [
|
|
254
|
+
# The traces their tests wait for, as Turborepo's plan of their tests reads them. Another
|
|
255
|
+
# package's trace is produced here, and a failure stops the launch, as a provider's; a trace
|
|
256
|
+
# of the plan waits for its build, and is produced with it below.
|
|
257
|
+
plan=$(cd "$copie" && monter npx --no-install turbo run test:vitest "${cibles[@]}" --dry=json) || exit 1
|
|
258
|
+
traces() { node --input-type=module -e "import { readFileSync } from 'node:fs'; import { tracesDuPlan } from '$ici/../turbo-des-paquets.mjs'; const [propres, ...plan] = process.argv.slice(1); console.log(tracesDuPlan(JSON.parse(readFileSync(0, 'utf8')), t => plan.includes(t.package) === (propres === 'oui')).join('\n'));" "$1" "${lesNoms[@]}" <<<"$plan"; }
|
|
238
259
|
autres=$(traces non) || exit 1
|
|
239
260
|
if [ -n "$autres" ]; then
|
|
240
261
|
mapfile -t ids <<<"$autres"
|
|
@@ -243,26 +264,29 @@ echec=$(mktemp)
|
|
|
243
264
|
propres=$(traces oui) || exit 1
|
|
244
265
|
ids=()
|
|
245
266
|
[ -z "$propres" ] || mapfile -t ids <<<"$propres"
|
|
246
|
-
# The
|
|
247
|
-
# built after
|
|
248
|
-
# Each task whose dependencies succeed goes to its end
|
|
249
|
-
#
|
|
250
|
-
# on it, which the envelope shows read-only.
|
|
251
|
-
if ! (cd "$copie" && monter npx --no-install turbo run build ${ids[@]+"${ids[@]}"} "
|
|
267
|
+
# The packages of the plan, their own traces, and what their tests read (the shared test
|
|
268
|
+
# material), built after their providers: a failure does not stop the launch, it goes into
|
|
269
|
+
# the instruction. Each task whose dependencies succeed goes to its end
|
|
270
|
+
# (--continue=dependencies-successful): one package's failure does not cancel the build of
|
|
271
|
+
# what the tests read without depending on it, which the envelope shows read-only.
|
|
272
|
+
if ! (cd "$copie" && monter npx --no-install turbo run build ${ids[@]+"${ids[@]}"} "${lecteurs[@]}" --continue=dependencies-successful) > "$echec" 2>&1; then
|
|
252
273
|
cat "$echec"
|
|
253
|
-
echo "⚠️ La construction
|
|
274
|
+
echo "⚠️ La construction du plan (${lesNoms[*]}) échoue : la séance s'ouvre, la consigne porte l'erreur."
|
|
254
275
|
else
|
|
255
276
|
: > "$echec"
|
|
256
277
|
fi
|
|
257
278
|
fi
|
|
258
279
|
fi
|
|
259
280
|
) >> "$journal" 2>&1 || { rm -f "$echec"; echo "⛔ La copie $copie n'a pas pu être préparée : voir $journal." >&2; exit "$CODE_COPIE"; }
|
|
260
|
-
# What the components before publish, read in the prepared copy,
|
|
261
|
-
|
|
281
|
+
# What the components before each package of the plan publish, read in the prepared copy,
|
|
282
|
+
# follows the instruction.
|
|
283
|
+
publie=$(cd "$copie" && node "$ici/../index-interfaces.mjs" --publie "$paquets" 2>> "$journal") \
|
|
262
284
|
|| { rm -f "$echec"; echo "⛔ Ce que publient les composants d'avant n'a pas pu se lire : voir $journal." >&2; exit "$CODE_COPIE"; }
|
|
263
285
|
# The session's working directory, the one the envelope gives as TMPDIR, follows them.
|
|
264
286
|
travail=$(node --input-type=module -e "import { dossierDeTravail } from '$ici/enveloppe.mjs'; process.stdout.write(dossierDeTravail(process.argv[1]));" "$copie" 2>> "$journal") \
|
|
265
287
|
|| { rm -f "$echec"; echo "⛔ Le dossier de travail de la séance n'a pas pu se lire : voir $journal." >&2; exit "$CODE_COPIE"; }
|
|
288
|
+
# The mark a lock leaves there when it stops the session out of the plan: none before the session.
|
|
289
|
+
rm -f "$travail/hors-plan"
|
|
266
290
|
dossier=$'\n\n'"## Ton dossier de travail"$'\n\n'"Tout fichier temporaire s'écrit dans \`$travail\`, que \`\$TMPDIR\` nomme aussi."
|
|
267
291
|
construction=
|
|
268
292
|
if [ -s "$echec" ]; then
|
|
@@ -293,7 +317,7 @@ schema=$(node "$ici/../resultats.mjs" --schema "$role" 2> /dev/null) || schema=
|
|
|
293
317
|
# An envelope in error does not stop the launcher (set -e): its code is kept for the exit.
|
|
294
318
|
code=0
|
|
295
319
|
lancer_claude() {
|
|
296
|
-
node "$ici/enveloppe.mjs" "$copie" "$
|
|
320
|
+
node "$ici/enveloppe.mjs" "$copie" "$paquets" "$role" -- \
|
|
297
321
|
"${CLAUDE_BIN:-claude}" -p --agent "$role" \
|
|
298
322
|
${surcharge[@]+"${surcharge[@]}"} ${fiche[@]+"${fiche[@]}"} --permission-mode bypassPermissions \
|
|
299
323
|
"${droits_du_role[@]}" < "$prompt"
|
|
@@ -305,6 +329,12 @@ else
|
|
|
305
329
|
lancer_claude >> "$journal" 2>&1 || code=$?
|
|
306
330
|
fi
|
|
307
331
|
rm -f "$prompt"
|
|
332
|
+
# A session its lock stopped out of the plan (scripts/verrous/verrou.mjs): its reason goes to the
|
|
333
|
+
# circuit, and to the log.
|
|
334
|
+
if [ -f "$travail/hors-plan" ]; then
|
|
335
|
+
mv "$travail/hors-plan" "$hors_plan"
|
|
336
|
+
{ cat "$hors_plan"; echo; } >> "$journal"
|
|
337
|
+
fi
|
|
308
338
|
echo "$code" > "$fin"
|
|
309
339
|
# The envelope ended: the session's line goes to the register from outside it, whatever its end hook did.
|
|
310
340
|
node "$ici/../registre.mjs" --copie "$copie" >> "$journal" 2>&1 || true
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The packages of the plan of the envelope a command runs in. The envelope names them to every
|
|
2
|
+
// command of its session, in the variable `GRILLHOUSE_ENVELOPPE`: the list of the paths the plan
|
|
3
|
+
// names inside the copy (`packages/a`, or `src/parser` in a one-package project), joined by the
|
|
4
|
+
// separator of a list of paths (`path.delimiter`, as NODE_PATH and PATH join theirs). As the
|
|
5
|
+
// visibility of Bazel and the module boundaries of Nx refuse a dependency while the code stays
|
|
6
|
+
// readable, the session reads the whole copy and writes these packages only: a command of the
|
|
7
|
+
// frame that reads the list builds, judges and writes them alone.
|
|
8
|
+
//
|
|
9
|
+
// This module uses Node alone, as the modules of scripts/paquets.mjs.
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
|
|
12
|
+
export const VARIABLE = 'GRILLHOUSE_ENVELOPPE';
|
|
13
|
+
// The file the lock of a session leaves in its working directory when it stops the session on a
|
|
14
|
+
// write out of the plan (scripts/verrous/verrou.mjs); the launcher hands it to the circuit as
|
|
15
|
+
// `<copie>.hors-plan` (scripts/enveloppe/lancer.sh).
|
|
16
|
+
export const MARQUE_HORS_PLAN = 'hors-plan';
|
|
17
|
+
|
|
18
|
+
// The list <paquets> as the variable carries it.
|
|
19
|
+
export const ecrireLaListe = paquets => paquets.join(path.delimiter);
|
|
20
|
+
|
|
21
|
+
// The list the text <texte> of the variable carries.
|
|
22
|
+
export const lireLaListe = texte =>
|
|
23
|
+
String(texte ?? '')
|
|
24
|
+
.split(path.delimiter)
|
|
25
|
+
.filter(Boolean);
|
|
26
|
+
|
|
27
|
+
// The packages of the plan of the envelope named in <env>, or null outside an envelope.
|
|
28
|
+
export const paquetsDeLEnveloppe = (env = process.env) =>
|
|
29
|
+
env[VARIABLE] ? lireLaListe(env[VARIABLE]) : null;
|
|
30
|
+
|
|
31
|
+
// The directory of the package of <paquetsDeLaCopie> (`paquets` of scripts/paquets.mjs, each
|
|
32
|
+
// `dossier` relative to the copy) that holds the path <chemin> of the copy, the deepest; `.`, the
|
|
33
|
+
// root, when none holds it.
|
|
34
|
+
export function paquetQuiTient(chemin, paquetsDeLaCopie) {
|
|
35
|
+
const rel = path.normalize(chemin).replace(/\/+$/, '');
|
|
36
|
+
const tenants = paquetsDeLaCopie
|
|
37
|
+
.map(p => path.normalize(p.dossier))
|
|
38
|
+
.filter(d => rel === d || rel.startsWith(`${d}/`));
|
|
39
|
+
return tenants.sort((a, b) => b.length - a.length)[0] ?? '.';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The directories, relative to the copy, that the plan <paquets> writes, sorted: for each path of
|
|
43
|
+
// the plan, the package that holds it (`paquetQuiTient`). A path that no package holds (a folder of
|
|
44
|
+
// the root, `scripts`; `src/parser` in a one-package project; `.`) writes the package that holds
|
|
45
|
+
// it, the root: the plan then writes the whole copy, `['.']`.
|
|
46
|
+
export function ecritsDuPlan(paquets, paquetsDeLaCopie) {
|
|
47
|
+
const ecrits = [...new Set(paquets.map(p => paquetQuiTient(p, paquetsDeLaCopie)))].sort();
|
|
48
|
+
return ecrits.includes('.') ? ['.'] : ecrits;
|
|
49
|
+
}
|