@ogygie/cli 0.16.0 → 0.17.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/dist/cli.js +12 -0
- package/package.json +2 -2
- package/templates/project/AGENTS.md +32 -15
- package/templates/project/design/patterns.md +17 -9
package/dist/cli.js
CHANGED
|
@@ -15940,6 +15940,18 @@ var governedChecksumsByVersion = {
|
|
|
15940
15940
|
"scripts/verify-specs.ts": "03d58baa11822ad7ae67080f990f7a82f4f94d223b12777728b8b9ddd7ebd843",
|
|
15941
15941
|
"tsconfig.base.json": "0f8919e9ed8bbc88e0308fa2fa91471dabb18d1df721bd78c04076597eba89a2"
|
|
15942
15942
|
},
|
|
15943
|
+
"0.17.0": {
|
|
15944
|
+
".github/workflows/ogygie-gates.yml": "48c40efe9fe66dd0f9c3b94287026d80eae9afd6782b5833fdf8846d8662babf",
|
|
15945
|
+
"AGENTS.md": "e058a54ff4750abf19f7c4b026e8be661d8ce25419596d22c20de2c387469370",
|
|
15946
|
+
"CLAUDE.md": "785ee8d90e368806d8cf0b4d84a15f29d1dc961168bda86cf1a6c60a923c8c9b",
|
|
15947
|
+
"scripts/lint-interdits.ts": "4644e1aaabc1d19ed42a0bdf8e2e55b9451f789d87d59754bce3432de7c357e7",
|
|
15948
|
+
"scripts/ogygie-design-brief.ts": "aba1585717b30808dd0bc8930a37a1ad2d83ee6869f969dbd06ca595e37a4a89",
|
|
15949
|
+
"scripts/ogygie-impact.ts": "f06cc8b4a46ddfbcfb32ba747c2454548ca49918123d04ab13d210b4a89c1fb9",
|
|
15950
|
+
"scripts/verify-contracts.ts": "9cd64c88dcc3b54b65bf1e1b7a68eb00353ee16f2a9ce8bca3c49ba063c2a08b",
|
|
15951
|
+
"scripts/verify-manifest.ts": "6c448fa3a19b87666f686ca57c6ca834d9e169b1380e4fe6e4c19b995bf94f3c",
|
|
15952
|
+
"scripts/verify-specs.ts": "03d58baa11822ad7ae67080f990f7a82f4f94d223b12777728b8b9ddd7ebd843",
|
|
15953
|
+
"tsconfig.base.json": "0f8919e9ed8bbc88e0308fa2fa91471dabb18d1df721bd78c04076597eba89a2"
|
|
15954
|
+
},
|
|
15943
15955
|
"0.2.0": {
|
|
15944
15956
|
".github/workflows/ogygie-gates.yml": "48c40efe9fe66dd0f9c3b94287026d80eae9afd6782b5833fdf8846d8662babf",
|
|
15945
15957
|
"AGENTS.md": "ca73ab619d8c55fac11858d815bf5fbab6537ecebe7ae4123cbdeb3e3e36bf1a",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ogygie/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Ogygie framework CLI: deterministic scaffolding (init), governed-file upgrades (upgrade) and lockstep verification (check) for Ogygie products.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@ogygie/core": "0.
|
|
20
|
+
"@ogygie/core": "0.17.0",
|
|
21
21
|
"@types/node": "^24.0.0",
|
|
22
22
|
"esbuild": "^0.28.0",
|
|
23
23
|
"tsx": "^4.20.0",
|
|
@@ -295,12 +295,19 @@ dérogation qui s'oublie. Elle ne couvre JAMAIS le code du produit lui-même.
|
|
|
295
295
|
### Stack imposée (toute autre lib = amendement DECISIONS.md d'abord)
|
|
296
296
|
Vite + React 19 + TanStack Router (routing EN CODE) + TanStack Query (état serveur) ;
|
|
297
297
|
PAS de lib d'état client (useState suffit) ; Tailwind v4 thémé depuis `design/tokens.json`
|
|
298
|
-
(valeurs arbitraires `p-[13px]` interdites par lint) ;
|
|
299
|
-
`
|
|
300
|
-
|
|
301
|
-
|
|
298
|
+
(valeurs arbitraires `p-[13px]` interdites par lint) ; le socle de patterns vient du
|
|
299
|
+
paquet `@ogygie/ui` — `ScreenState`, `EmptyState`, `ErrorBanner`, `EditableText`,
|
|
300
|
+
`fetchContract`, et derrière leur propre point d'entrée `DataTable`
|
|
301
|
+
(`@ogygie/ui/data-table`), `ContractForm` (`@ogygie/ui/contract-form`),
|
|
302
|
+
`VarianceChart` (`@ogygie/ui/variance-chart`) — IMPORTÉ, jamais recopié ; les
|
|
303
|
+
patterns PRODUIT vivent dans `apps/web/src/patterns/` (jamais consommés directement
|
|
304
|
+
depuis node_modules par une feature) ; react-hook-form UNIQUEMENT via `ContractForm` ;
|
|
305
|
+
TanStack Table UNIQUEMENT via `DataTable` ; Recharts UNIQUEMENT via `VarianceChart` ;
|
|
302
306
|
date-fns via les helpers `@ogygie/core` (jamais de `new Date()` nu) ; i18n Lingui
|
|
303
|
-
(ICU, extraction vérifiée en CI)
|
|
307
|
+
(ICU, extraction vérifiée en CI) — `@ogygie/ui` ne porte AUCUNE chaîne : tout texte
|
|
308
|
+
lui arrive en prop, traduit par la feature. Noms de patterns en anglais. La feuille
|
|
309
|
+
Tailwind du produit déclare le paquet comme source
|
|
310
|
+
(`@source "../node_modules/@ogygie/ui/src";`), sinon ses classes ne sont pas générées.
|
|
304
311
|
|
|
305
312
|
### Structure d'une feature front (miroir de l'API)
|
|
306
313
|
```
|
|
@@ -319,7 +326,7 @@ apps/web/features/orders/
|
|
|
319
326
|
/** @intent Data access of the orders feature. Re-validates contracts in dev. */
|
|
320
327
|
import { useQuery } from "@tanstack/react-query";
|
|
321
328
|
import { ListOrdersOutputSchema } from "@product/api/features/orders/schemas";
|
|
322
|
-
import { fetchContract } from "
|
|
329
|
+
import { fetchContract } from "@ogygie/ui"; // Zod parse of the answer; an OgygieFailure on a refused call or a broken contract
|
|
323
330
|
|
|
324
331
|
export function useOrders() {
|
|
325
332
|
return useQuery({
|
|
@@ -334,18 +341,25 @@ export function useOrders() {
|
|
|
334
341
|
// apps/web/features/orders/OrdersList.tsx
|
|
335
342
|
/** @intent Orders list screen: composition of patterns, zero business logic. */
|
|
336
343
|
import { Trans } from "@lingui/react/macro";
|
|
337
|
-
import {
|
|
338
|
-
import {
|
|
339
|
-
import { ErrorBanner } from "../../patterns/ErrorBanner";
|
|
344
|
+
import { ScreenState } from "@ogygie/ui";
|
|
345
|
+
import { DataTable } from "@ogygie/ui/data-table";
|
|
340
346
|
import { useOrders } from "./queries";
|
|
341
347
|
|
|
342
348
|
export function OrdersList() {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
+
return (
|
|
350
|
+
<ScreenState
|
|
351
|
+
query={useOrders()}
|
|
352
|
+
errorTitle={<Trans>Cette vue n'a pas pu être chargée</Trans>}
|
|
353
|
+
loading={<DataTable.Skeleton />}
|
|
354
|
+
isEmpty={(data) => data.orders.length === 0}
|
|
355
|
+
emptyState={{
|
|
356
|
+
title: <Trans>Ajoutez votre première commande</Trans>,
|
|
357
|
+
explanation: <Trans>Les commandes enregistrées apparaissent ici.</Trans>,
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
{(data) => <DataTable rows={data.orders} columns={orderColumns} rowKey={(order) => order.id} />}
|
|
361
|
+
</ScreenState>
|
|
362
|
+
);
|
|
349
363
|
}
|
|
350
364
|
```
|
|
351
365
|
|
|
@@ -353,6 +367,9 @@ export function OrdersList() {
|
|
|
353
367
|
- Un écran est une COMPOSITION de patterns : jamais de `<table>`, `<form>` ou fetch nus
|
|
354
368
|
dans une feature. Si un pattern manque, on le crée dans `patterns/` (et on met à jour
|
|
355
369
|
`design/patterns.md`), on ne bricole pas dans la feature.
|
|
370
|
+
- Les états d'un écran — accès refusé, erreur, chargement, vide — passent par
|
|
371
|
+
`ScreenState`, jamais par une cascade de `if` propre à l'écran : le corps ne reçoit
|
|
372
|
+
que des données servies.
|
|
356
373
|
- Chaque état UI listé dans la spec (vide/chargement/nominal/erreur) a son test.
|
|
357
374
|
- Toute chaîne visible passe par Lingui (`<Trans>`/`t`) — la CI casse sinon.
|
|
358
375
|
- Chiffres financiers : `tabular-nums`, alignés à droite, unité explicite.
|
|
@@ -2,27 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
> Les patterns sont les SEULES briques d'écran autorisées (AGENTS.md §Front) :
|
|
4
4
|
> un écran est une COMPOSITION de patterns, jamais de `<table>`, `<form>` ni
|
|
5
|
-
> fetch nus.
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
>
|
|
5
|
+
> fetch nus. Les patterns GÉNÉRIQUES ci-dessous sont LIVRÉS par le paquet
|
|
6
|
+
> `@ogygie/ui` : un produit les importe, il ne les recopie pas, et leur fiche
|
|
7
|
+
> ci-dessous est leur contrat. Un pattern PRODUIT — propre au domaine — naît
|
|
8
|
+
> dans `apps/web/src/patterns/` avec sa fiche ICI d'abord, jamais en one-off
|
|
9
|
+
> dans un écran. Tout texte lu par un humain arrive à un pattern générique en
|
|
10
|
+
> prop, traduit par la feature (Lingui) : le paquet ne porte aucune chaîne.
|
|
9
11
|
>
|
|
10
12
|
> Ce catalogue est une source de vérité du brief de design
|
|
11
13
|
> (`pnpm ogygie:design-brief <feature>`) : chaque fiche `## <Name>` devient
|
|
12
14
|
> une entrée du vocabulaire de composition. Noms en anglais (machine-lisible),
|
|
13
15
|
> fiches en français (document humain).
|
|
14
16
|
|
|
17
|
+
## ScreenState
|
|
18
|
+
Le composant d'état UNIQUE d'un écran (`@ogygie/ui`). Reçoit la lecture (`QueryLike`, sous-ensemble d'un résultat TanStack Query) et le corps en fonction de rendu, et décide dans cet ordre : accès refusé (`denied` de l'appelant, ou une réponse 401/403 quand une copie `accessDenied` est donnée), erreur (`ErrorBanner`, titré par `errorTitle`), chargement (`loading`, à défaut `Skeleton`), vide (`isEmpty` + `emptyState`, un `EmptyState` avec son action), puis le corps avec des données servies. Un corps ne branche jamais sur `undefined`.
|
|
19
|
+
|
|
15
20
|
## DataTable
|
|
16
|
-
Tableau de données (TanStack Table
|
|
21
|
+
Tableau de données (`@ogygie/ui/data-table`, TanStack Table — seul usage autorisé). Colonnes typées `{ id, header, cell, sortValue?, align? }` ; tri par clic d'en-tête (`aria-sort`), chiffres `align: "end"` en `tabular-nums` alignés à droite, unité explicite dans la cellule. États : squelette de chargement (`DataTable.Skeleton`), vide DÉLÉGUÉ (`emptyState` : un `EmptyState` qui dit pourquoi), nominal trié ; l'erreur appartient à `ScreenState`. La liste de colonnes reste stable (module ou `useMemo`).
|
|
17
22
|
|
|
18
23
|
## EmptyState
|
|
19
|
-
État vide intentionnel : un titre, une explication
|
|
24
|
+
État vide intentionnel (`@ogygie/ui`) : un titre qui nomme la CAUSE, une explication qui dit ce qui le remplirait, UNE action de création au plus. Jamais de tableau ou de liste vides nus — l'écran vide est le premier écran que voit chaque nouvel utilisateur. Deux causes, deux formulations : rien d'enregistré, ou un filtre qui ne trouve rien.
|
|
20
25
|
|
|
21
26
|
## ErrorBanner
|
|
22
|
-
Bandeau d'erreur
|
|
27
|
+
Bandeau d'erreur (`@ogygie/ui`) : affiche une `OgygieFailure` en entier — le titre du produit, le message, le code stable avec le statut et la cause, la correction suggérée — et dégrade toute autre erreur à son message. `kind: "save"` marque une écriture refusée (le produit titre autrement) ; `retry` ajoute le bouton que le produit libelle. Tout état d'erreur d'écran passe par lui — jamais de message improvisé.
|
|
23
28
|
|
|
24
29
|
## ContractForm
|
|
25
|
-
Formulaire DÉRIVÉ d'un contrat Zod (react-hook-form
|
|
30
|
+
Formulaire DÉRIVÉ d'un contrat Zod (`@ogygie/ui/contract-form`, react-hook-form — seul usage autorisé) : les champs viennent de la forme du schéma, leurs contrôles de leur genre (texte, nombre, date, sélection d'enum, case à cocher), leurs contraintes des bornes du schéma — rien n'est redéclaré à la main — et le schéma valide chaque soumission (`safeParse`). Libellés, aides, libellés d'options, `submitLabel` et `cancel` sont des props traduites ; `renderIssue` traduit la phrase d'un refus. États : saisie, soumission en cours (bouton inactif, `pending`), erreur de champ (une phrase sous le champ), erreur de formulaire (un `refine`), erreur serveur (`error` : un `ErrorBanner` save au-dessus des actions). `onSubmit` reçoit la SORTIE parsée du contrat.
|
|
26
31
|
|
|
27
32
|
## VarianceChart
|
|
28
|
-
Graphique d'écart (Recharts
|
|
33
|
+
Graphique d'écart (`@ogygie/ui/variance-chart`, Recharts — seul usage autorisé) : une valeur constatée (`measured`) contre une référence (`reference`), par libellé, en deux barres groupées ; l'écart signé se lit dans l'infobulle ; une ligne zéro quand les valeurs la traversent. Couleurs tirées des tokens du produit par variables CSS, noms de séries et unité en props traduites. États : vide DÉLÉGUÉ (`emptyState`), squelette (`VarianceChart.Skeleton`) ; chargement et erreur appartiennent à `ScreenState`. Montants en `tabular-nums`, axe et unité toujours étiquetés.
|
|
34
|
+
|
|
35
|
+
## EditableText
|
|
36
|
+
Texte qui s'écrit là où il se lit (`@ogygie/ui`) : un clic le transforme en champ, quitter le champ ou Entrée enregistre, Échap abandonne. Un lecteur sans droit voit le texte nu, jamais un contrôle inactif. Un brouillon blanc est refusé sans écriture (sauf `allowEmpty`) ; une borne (`maxLength`) arrête le champ et affiche le compteur ; `pending` rend le contrôle inactif le temps d'une écriture. `placeholder` et `ariaLabel` sont traduits par la feature.
|