@roomi-fields/grillhouse 0.0.0-stage → 0.23.1
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 +9 -0
- package/METACADRE.md +41 -0
- package/agents/developpeur.md +10 -0
- package/agents/explorateur.md +9 -0
- package/agents/questionneur.md +11 -0
- package/agents/referent-technique.md +9 -0
- package/agents/regulateur.md +11 -0
- package/agents/relecteur.md +9 -0
- package/agents/testwriter.md +10 -0
- package/bin/grillhouse.mjs +125 -0
- package/cadre/templates/projet/.claude/settings.json +30 -0
- package/cadre/templates/projet/.editorconfig +47 -0
- package/cadre/templates/projet/.env.example +57 -0
- package/cadre/templates/projet/.eslintrc.cjs +56 -0
- package/cadre/templates/projet/.github/workflows/ci.yml +66 -0
- package/cadre/templates/projet/.mcp.json +13 -0
- package/cadre/templates/projet/.prettierrc +11 -0
- package/cadre/templates/projet/CHANGELOG.md +61 -0
- package/cadre/templates/projet/CLAUDE.md +46 -0
- package/cadre/templates/projet/CONTRIBUTING.md +243 -0
- package/cadre/templates/projet/CREDITS.md +41 -0
- package/cadre/templates/projet/README.md +152 -0
- package/cadre/templates/projet/_gitignore +91 -0
- package/cadre/templates/projet/_npmignore +46 -0
- package/cadre/templates/projet/deployment/README.md +98 -0
- package/cadre/templates/projet/deployment/docs/01-INSTALL.md +145 -0
- package/cadre/templates/projet/deployment/docs/02-CONFIGURATION.md +117 -0
- package/cadre/templates/projet/deployment/docs/03-API.md +264 -0
- package/cadre/templates/projet/deployment/docs/04-TROUBLESHOOTING.md +262 -0
- package/cadre/templates/projet/deployment/scripts/install.ps1 +100 -0
- package/cadre/templates/projet/deployment/scripts/start.ps1 +61 -0
- package/cadre/templates/projet/deployment/scripts/stop.ps1 +37 -0
- package/cadre/templates/projet/deployment/scripts/test.ps1 +118 -0
- package/cadre/templates/projet/docs/agents/issue-tracker.md +44 -0
- package/cadre/templates/projet/ecosystem.config.cjs +73 -0
- package/cadre/templates/projet/package.json +90 -0
- package/cadre/templates/projet/pitmaster/SUIVI.md +22 -0
- package/cadre/templates/projet/src/config.ts +68 -0
- package/cadre/templates/projet/src/errors.ts +102 -0
- package/cadre/templates/projet/src/index.ts +46 -0
- package/cadre/templates/projet/src/services/.gitkeep +8 -0
- package/cadre/templates/projet/src/types/index.ts +24 -0
- package/cadre/templates/projet/src/utils/logger.ts +106 -0
- package/cadre/templates/projet/tests/integration/.gitkeep +7 -0
- package/cadre/templates/projet/tests/unit/config.spec.ts +68 -0
- package/cadre/templates/projet/tests/unit/errors.spec.ts +132 -0
- package/cadre/templates/projet/tests/unit/types.spec.ts +73 -0
- package/cadre/templates/projet/tsconfig.eslint.json +9 -0
- package/cadre/templates/projet/tsconfig.json +41 -0
- package/cadre/templates/projet/tsdoc.json +6 -0
- package/cadre/templates/projet/vitest.config.ts +44 -0
- package/cadre/templates/turbo/paquets.json +29 -0
- package/cadre/templates/turbo/sans-paquets.json +28 -0
- package/charte.md +107 -0
- package/docs/ARCHITECTURE.md +90 -0
- package/hooks/crochet.mjs +33 -0
- package/hooks/hooks.json +58 -0
- package/hooks/register.tsx +558 -0
- package/package.json +75 -4
- package/scripts/avancement.mjs +244 -0
- package/scripts/bilan.mjs +523 -0
- package/scripts/branche-de-nuit.mjs +59 -0
- package/scripts/cadre.mjs +109 -0
- package/scripts/circuit.mjs +4375 -0
- package/scripts/code-mort.mjs +371 -0
- package/scripts/composants-affectes.mjs +598 -0
- package/scripts/consommateurs-arbitres.mjs +192 -0
- package/scripts/consommateurs.mjs +310 -0
- package/scripts/crochet.mjs +24 -0
- package/scripts/crochets.mjs +135 -0
- package/scripts/dernier-vert.mjs +208 -0
- package/scripts/dette.mjs +181 -0
- package/scripts/droits.mjs +354 -0
- package/scripts/enveloppe/codes.mjs +17 -0
- package/scripts/enveloppe/composant.mjs +11 -0
- package/scripts/enveloppe/enveloppe.mjs +628 -0
- package/scripts/enveloppe/lancer.sh +311 -0
- package/scripts/etapes.mjs +323 -0
- package/scripts/etat-du-circuit.mjs +104 -0
- package/scripts/frontieres.mjs +456 -0
- package/scripts/gardes-du-cadre.mjs +72 -0
- package/scripts/greffons.mjs +338 -0
- package/scripts/grillhouse-maj.mjs +514 -0
- package/scripts/index-interfaces.mjs +293 -0
- package/scripts/init.mjs +117 -0
- package/scripts/integration/file-attente.mjs +61 -0
- package/scripts/integration/file.mjs +494 -0
- package/scripts/integration/integrer.mjs +381 -0
- package/scripts/integration/rejeu.mjs +139 -0
- package/scripts/integration/verdict.mjs +13 -0
- package/scripts/interfaces-contre-code.mjs +547 -0
- package/scripts/ligne-etat/defaut.sh +110 -0
- package/scripts/ligne-etat/ligne-etat.mjs +93 -0
- package/scripts/migrations/0.23.0-charte-importee.mjs +47 -0
- package/scripts/migrations/0.23.0-config-vitest.mjs +105 -0
- package/scripts/migrations/0.23.0-crochets-de-seance.mjs +55 -0
- package/scripts/migrations/0.23.0-marche-du-projet.mjs +82 -0
- package/scripts/migrations.mjs +43 -0
- package/scripts/nuit.sh +269 -0
- package/scripts/paquets.mjs +79 -0
- package/scripts/poussee-cles.mjs +46 -0
- package/scripts/preparation.mjs +84 -0
- package/scripts/references-par-les-types.mjs +420 -0
- package/scripts/registre.mjs +336 -0
- package/scripts/resultats.mjs +580 -0
- package/scripts/resumes.mjs +57 -0
- package/scripts/retirer-copie.sh +127 -0
- package/scripts/session-start.sh +203 -0
- package/scripts/sortie.mjs +155 -0
- package/scripts/sous-modules.sh +316 -0
- package/scripts/structure-guard.sh +27 -0
- package/scripts/superviseur.mjs +102 -0
- package/scripts/tableau.mjs +1886 -0
- package/scripts/tests.mjs +236 -0
- package/scripts/ticket.sh +23 -0
- package/scripts/turbo-des-paquets.mjs +899 -0
- package/scripts/un-commit-par-ticket.mjs +212 -0
- package/scripts/verifier.mjs +469 -0
- package/scripts/verrou-de-fichier.mjs +130 -0
- package/scripts/verrou-de-machine.mjs +211 -0
- package/scripts/verrous/commande.mjs +180 -0
- package/scripts/verrous/ticket-du-sous-agent.mjs +39 -0
- package/scripts/verrous/verrou.mjs +165 -0
- package/scripts/vitest-config/avancement.mjs +39 -0
- package/scripts/vitest-config/avancement.reporter.mjs +56 -0
- package/scripts/vitest-config/base-de-passe.mjs +128 -0
- package/scripts/vitest-config/base.d.ts +6 -0
- package/scripts/vitest-config/base.mjs +87 -0
- package/scripts/vitest-config/changements.mjs +173 -0
- package/scripts/vitest-config/cibles.mjs +207 -0
- package/scripts/vitest-config/duree.reporter.mjs +98 -0
- package/scripts/vitest-config/machine.setup.mjs +14 -0
- package/scripts/vitest-config/mesure.d.ts +6 -0
- package/scripts/vitest-config/mesure.mjs +13 -0
- package/scripts/vitest-config/mesure.setup.mjs +12 -0
- package/scripts/vitest-config/pression.mjs +90 -0
- package/scripts/vitest-config/resultats.mjs +23 -0
- package/scripts/vitest-config/resultats.setup.mjs +19 -0
- package/scripts/vitest.nuit.config.mjs +26 -0
- package/skills/developpeur/SKILL.md +175 -0
- package/skills/explorateur/SKILL.md +84 -0
- package/skills/grill/SKILL.md +238 -0
- package/skills/grill/references/releve-structurel.md +38 -0
- package/skills/mesure/SKILL.md +168 -0
- package/skills/pitmaster/SKILL.md +382 -0
- package/skills/pitmaster/references/cadre.md +119 -0
- package/skills/pitmaster/references/consigne-agent.md +308 -0
- package/skills/pitmaster/references/erreurs.md +25 -0
- package/skills/pitmaster/references/tour.md +124 -0
- package/skills/questionneur/SKILL.md +64 -0
- package/skills/redacteur/SKILL.md +84 -0
- package/skills/redacteur/references/documents-d-un-composant.md +105 -0
- package/skills/referent-technique/SKILL.md +145 -0
- package/skills/regulateur/SKILL.md +220 -0
- package/skills/release/SKILL.md +134 -0
- package/skills/release/scripts/update-version.cjs +92 -0
- package/skills/relecteur/SKILL.md +152 -0
- package/skills/relecteur/references/LICENSE-MIT +30 -0
- package/skills/relecteur/references/SOURCE.md +8 -0
- package/skills/relecteur/references/claims-check.md +14 -0
- package/skills/relecteur/references/deletion-check.md +14 -0
- package/skills/relecteur/references/edge-case-hunter.md +80 -0
- package/skills/relecteur/references/verification-gap.md +113 -0
- package/skills/testwriter/SKILL.md +187 -0
- package/types/index.d.ts +56 -0
- package/README.md +0 -3
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// The progress of an automatic pass, in figures, as Bazel's counter of actions « [1 234 / 2 000] »
|
|
2
|
+
// and the steps of a CI: the files of tests done over planned, and the instant of the last sign,
|
|
3
|
+
// which the board shows (scripts/tableau.mjs), so that a pass that freezes is seen.
|
|
4
|
+
//
|
|
5
|
+
// - A pass has its progress directory, which the variable GRILLHOUSE_AVANCEMENT (AVANCEMENT of
|
|
6
|
+
// scripts/vitest-config/avancement.mjs) names to its commands: the circuit opens one for each
|
|
7
|
+
// automatic pass and names it in its state (scripts/circuit.mjs), `npm run verifier` opens its own when it
|
|
8
|
+
// receives none (scripts/verifier.mjs). The directory holds `passe.json` (`{ genre, debut,
|
|
9
|
+
// precedent }`: its kind, its start, the total of the previous pass of that kind), the records
|
|
10
|
+
// of its tasks (`taches/`, written by the reporter of progress of the base configuration, one
|
|
11
|
+
// per run of Vitest, and by the queue for the steps of its CI, scripts/integration/file.mjs),
|
|
12
|
+
// and the plans of its runs of Turborepo (`plan/`).
|
|
13
|
+
// - The reading adds the records: the files done, and the files planned of the tasks started;
|
|
14
|
+
// while every task the plans name has not started, the total of the previous pass of the same
|
|
15
|
+
// kind stands when it is greater (a pass without a plan never knows all its tasks started).
|
|
16
|
+
// The last sign is the latest writing of a record, or the start of the pass without one.
|
|
17
|
+
// - A plan: before a run of Turborepo that plays tests, its plan (`turbo run … --dry=json`) names
|
|
18
|
+
// the tasks of tests and those Turborepo replays from its cache; a task replayed counts its files
|
|
19
|
+
// as done at once, its number known by its hash from the pass that played it, as a cache of
|
|
20
|
+
// Bazel keeps the outcome of an action by its key.
|
|
21
|
+
// - The totals live in `<git common dir>/grillhouse/avancement.json`, one per repository, its
|
|
22
|
+
// copies included, beside the last green (scripts/dernier-vert.mjs): `{ passes, taches }`, the
|
|
23
|
+
// total of the last pass of each kind and the files planned of each task by its hash (the
|
|
24
|
+
// latest TACHES_GARDEES); each pass keeps its own at its end (`garderLeTotal`).
|
|
25
|
+
// - A measure out of a ticket (`npm run verifier` of a supervisor or of an integration) writes
|
|
26
|
+
// beside the lock of the machine (scripts/verrou-de-machine.mjs; the file of the lock with
|
|
27
|
+
// `.avancement.json` added, never the lock itself) its repository, its command, its progress
|
|
28
|
+
// directory and its process, removed at its end; the board reads it while that process lives
|
|
29
|
+
// and the lock is held (`lireLaMesure`).
|
|
30
|
+
import { spawnSync } from 'node:child_process';
|
|
31
|
+
import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
32
|
+
import { tmpdir } from 'node:os';
|
|
33
|
+
import path from 'node:path';
|
|
34
|
+
import { ecrireAtomique, TACHES } from './vitest-config/avancement.mjs';
|
|
35
|
+
import { verrouDeMachine } from './verrou-de-machine.mjs';
|
|
36
|
+
|
|
37
|
+
const PASSE = 'passe.json';
|
|
38
|
+
const PLAN = 'plan';
|
|
39
|
+
const TACHES_GARDEES = 2_000;
|
|
40
|
+
const TESTS = 'test:vitest';
|
|
41
|
+
|
|
42
|
+
const lireJson = f => {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(readFileSync(f, 'utf8'));
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const lister = d => {
|
|
50
|
+
try {
|
|
51
|
+
return readdirSync(d).filter(f => f.endsWith('.json'));
|
|
52
|
+
} catch {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// The file of the totals of the repository at <racine>, null out of git.
|
|
58
|
+
function fichierDesTotaux(racine) {
|
|
59
|
+
const r = spawnSync(
|
|
60
|
+
'git',
|
|
61
|
+
['-C', racine, 'rev-parse', '--path-format=absolute', '--git-common-dir'],
|
|
62
|
+
{
|
|
63
|
+
encoding: 'utf8',
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
return r.status === 0 ? path.join(r.stdout.trim(), 'grillhouse', 'avancement.json') : null;
|
|
67
|
+
}
|
|
68
|
+
const lireLesTotaux = racine => {
|
|
69
|
+
const f = fichierDesTotaux(racine);
|
|
70
|
+
const t = f ? lireJson(f) : null;
|
|
71
|
+
return { fichier: f, passes: t?.passes ?? {}, taches: t?.taches ?? {} };
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Opens the progress directory of a pass of kind <genre> (null: a pass whose total is not kept)
|
|
76
|
+
* in the repository at <racine>, made under <dans>, its start <debut>; its path.
|
|
77
|
+
* @param {{ racine: string, genre?: string | null, dans?: string, debut?: number }} o
|
|
78
|
+
*/
|
|
79
|
+
export function ouvrirAvancement({ racine, genre = null, dans = tmpdir(), debut = Date.now() }) {
|
|
80
|
+
const dossier = mkdtempSync(path.join(dans, 'avancement-'));
|
|
81
|
+
const precedent = genre ? (lireLesTotaux(racine).passes[genre] ?? null) : null;
|
|
82
|
+
ecrireAtomique(path.join(dossier, PASSE), { genre, debut, precedent });
|
|
83
|
+
return dossier;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Before a run of Turborepo of <args> in <racine> under <env>, while <dossier> is a progress
|
|
88
|
+
* directory: the plan of the run, its tasks of tests and those replayed from the cache, each of
|
|
89
|
+
* those counted done at once. A plan that does not read changes nothing.
|
|
90
|
+
* @param {string | undefined} dossier
|
|
91
|
+
* @param {{ racine: string, args: string[], env?: Record<string, string | undefined> }} o
|
|
92
|
+
*/
|
|
93
|
+
export function planifier(dossier, { racine, args, env = process.env }) {
|
|
94
|
+
if (!dossier) return;
|
|
95
|
+
const r = spawnSync('turbo', ['run', ...args.filter(a => a !== '--summarize'), '--dry=json'], {
|
|
96
|
+
cwd: racine,
|
|
97
|
+
env,
|
|
98
|
+
encoding: 'utf8',
|
|
99
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
100
|
+
});
|
|
101
|
+
let plan;
|
|
102
|
+
try {
|
|
103
|
+
plan = JSON.parse(r.stdout);
|
|
104
|
+
} catch {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const taches = (plan?.tasks ?? []).filter(t => t.task === TESTS && t.hash);
|
|
108
|
+
if (!taches.length) return;
|
|
109
|
+
const { taches: connues } = lireLesTotaux(racine);
|
|
110
|
+
try {
|
|
111
|
+
for (const t of taches.filter(x => x.cache?.status === 'HIT')) {
|
|
112
|
+
const n = connues[t.hash] ?? 0;
|
|
113
|
+
ecrireAtomique(path.join(dossier, TACHES, `cache-${t.hash}.json`), {
|
|
114
|
+
hash: t.hash,
|
|
115
|
+
faits: n,
|
|
116
|
+
prevus: n,
|
|
117
|
+
a: Date.now(),
|
|
118
|
+
cache: true,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
ecrireAtomique(path.join(dossier, PLAN, `${process.pid}-${Date.now()}.json`), {
|
|
122
|
+
hashes: taches.map(t => t.hash),
|
|
123
|
+
});
|
|
124
|
+
} catch {
|
|
125
|
+
// A directory that does not write leaves the pass going, without its progress.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// The records of <dossier>, one per task: a task Turborepo replayed and played anyway counts by
|
|
130
|
+
// the record of its run, a task played again by its latest.
|
|
131
|
+
function enregistrements(dossier) {
|
|
132
|
+
const parHash = new Map();
|
|
133
|
+
const sans = [];
|
|
134
|
+
for (const f of lister(path.join(dossier, TACHES))) {
|
|
135
|
+
const e = lireJson(path.join(dossier, TACHES, f));
|
|
136
|
+
if (!e || !Number.isFinite(e.faits) || !Number.isFinite(e.prevus)) continue;
|
|
137
|
+
if (!e.hash) sans.push(e);
|
|
138
|
+
else {
|
|
139
|
+
const avant = parHash.get(e.hash);
|
|
140
|
+
if (!avant || (!e.cache && (avant.cache || e.a > avant.a))) parHash.set(e.hash, e);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return [...parHash.values(), ...sans];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The progress of the pass whose directory is <dossier>: its files done and planned, and the
|
|
148
|
+
* instant of its last sign (ms); null when the directory does not read.
|
|
149
|
+
* @param {string} dossier
|
|
150
|
+
* @returns {{ faits: number, prevus: number, dernier: number } | null}
|
|
151
|
+
*/
|
|
152
|
+
export function lireAvancement(dossier) {
|
|
153
|
+
const passe = lireJson(path.join(dossier, PASSE));
|
|
154
|
+
if (!passe) return null;
|
|
155
|
+
const liste = enregistrements(dossier);
|
|
156
|
+
const faits = liste.reduce((s, e) => s + e.faits, 0);
|
|
157
|
+
const demarres = liste.reduce((s, e) => s + e.prevus, 0);
|
|
158
|
+
const planifies = new Set(
|
|
159
|
+
lister(path.join(dossier, PLAN)).flatMap(
|
|
160
|
+
f => lireJson(path.join(dossier, PLAN, f))?.hashes ?? []
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
const vus = new Set(liste.map(e => e.hash).filter(Boolean));
|
|
164
|
+
const tous = planifies.size > 0 && [...planifies].every(h => vus.has(h));
|
|
165
|
+
const prevus = tous ? demarres : Math.max(demarres, passe.precedent ?? 0);
|
|
166
|
+
const debut = Number(passe.debut) || 0;
|
|
167
|
+
const dernier = Math.max(debut, ...liste.map(e => Number(e.a) || 0));
|
|
168
|
+
return { faits, prevus, debut, dernier };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Keeps, at the end of the pass whose directory is <dossier>, its total under its kind and the
|
|
173
|
+
* files planned of each task it played, in the totals of the repository at <racine>.
|
|
174
|
+
* @param {string} dossier
|
|
175
|
+
* @param {string} racine
|
|
176
|
+
*/
|
|
177
|
+
export function garderLeTotal(dossier, racine) {
|
|
178
|
+
const passe = lireJson(path.join(dossier, PASSE));
|
|
179
|
+
if (!passe) return;
|
|
180
|
+
const t = lireLesTotaux(racine);
|
|
181
|
+
if (!t.fichier) return;
|
|
182
|
+
const liste = enregistrements(dossier);
|
|
183
|
+
if (passe.genre && liste.length) t.passes[passe.genre] = liste.reduce((s, e) => s + e.prevus, 0);
|
|
184
|
+
for (const e of liste.filter(x => x.hash && !x.cache)) {
|
|
185
|
+
delete t.taches[e.hash];
|
|
186
|
+
t.taches[e.hash] = e.prevus;
|
|
187
|
+
}
|
|
188
|
+
const cles = Object.keys(t.taches);
|
|
189
|
+
for (const c of cles.slice(0, Math.max(0, cles.length - TACHES_GARDEES))) delete t.taches[c];
|
|
190
|
+
try {
|
|
191
|
+
ecrireAtomique(t.fichier, { passes: t.passes, taches: t.taches });
|
|
192
|
+
} catch {
|
|
193
|
+
// A place that does not write keeps no total: the next pass counts without it.
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// The file of the measure out of a ticket under <env>: beside the lock of the machine.
|
|
198
|
+
function fichierDeLaMesure(env = process.env) {
|
|
199
|
+
const verrou = verrouDeMachine(env);
|
|
200
|
+
return { verrou, fichier: `${verrou}.avancement.json` };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Names beside the lock of the machine the measure out of a ticket that runs: the repository
|
|
205
|
+
* <depot>, the command <commande>, its progress directory <dossier>, this process; a function that
|
|
206
|
+
* removes it.
|
|
207
|
+
* @param {{ env?: Record<string, string | undefined>, depot: string, commande: string, dossier: string }} o
|
|
208
|
+
* @returns {() => void}
|
|
209
|
+
*/
|
|
210
|
+
export function ecrireLaMesure({ env = process.env, depot, commande, dossier }) {
|
|
211
|
+
const { fichier } = fichierDeLaMesure(env);
|
|
212
|
+
try {
|
|
213
|
+
mkdirSync(path.dirname(fichier), { recursive: true });
|
|
214
|
+
ecrireAtomique(fichier, { depot, commande, dossier, pid: process.pid });
|
|
215
|
+
} catch {
|
|
216
|
+
return () => {};
|
|
217
|
+
}
|
|
218
|
+
return () => {
|
|
219
|
+
if (lireJson(fichier)?.pid === process.pid) rmSync(fichier, { force: true });
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const vivant = pid => {
|
|
224
|
+
try {
|
|
225
|
+
process.kill(pid, 0);
|
|
226
|
+
return true;
|
|
227
|
+
} catch (e) {
|
|
228
|
+
return e.code === 'EPERM';
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* The measure out of a ticket that holds the lock of the machine under <env>: its repository, its
|
|
234
|
+
* command and its progress; null without one, or when its process is gone or the lock is not held.
|
|
235
|
+
* @param {Record<string, string | undefined>} [env]
|
|
236
|
+
*/
|
|
237
|
+
export function lireLaMesure(env = process.env) {
|
|
238
|
+
const { verrou, fichier } = fichierDeLaMesure(env);
|
|
239
|
+
const m = lireJson(fichier);
|
|
240
|
+
if (!m || !Number.isInteger(m.pid) || !vivant(m.pid) || !existsSync(verrou)) return null;
|
|
241
|
+
const a = typeof m.dossier === 'string' ? lireAvancement(m.dossier) : null;
|
|
242
|
+
if (!a) return null;
|
|
243
|
+
return { depot: String(m.depot ?? ''), commande: String(m.commande ?? ''), ...a };
|
|
244
|
+
}
|