baldart 4.83.0 → 4.84.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/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.84.0] - 2026-07-01
9
+
10
+ **`/ds-handoff` decision & preference pass — anticipa le domande di Claude Design invece di rimandargliele.** Il prompt field-level di `ds-handoff` copriva un solo asse (correttezza dei *campi* via field-extraction + coverage gate) e lasciava scoperto il **secondo asse — le decisioni di design aperte + le preferenze di consegna** — che è esattamente ciò su cui Claude Design rimanda le domande all'utente (nel caso reale "Hub fornitore", 6 domande su 6 erano su questo asse, zero sui campi). Una era **auto-inflitta** (il PRD diceva *"da proporre"* e la skill l'ha inoltrata testualmente), un'altra su un fatto **già in mano alla skill** (enum categoria con `color`) mai tradotto in istruzione.
11
+
12
+ Il fix è **combinato**: (1) un nuovo **Step 5.5 — Decision & preference pass** (`references/decision-pass.md`) che risolve PRIMA di emettere le scelte aperte / formato consegna / scope stati / canvas / varianti — **triggered, non always-on** (stessa filosofia del BLOCK del coverage gate: parte solo se c'è un irrisolto, UNA `AskUserQuestion` consolidata, no-op quando nulla è aperto; per le decisioni aperte offre "decido io" vs "fai proporre N opzioni a Claude Design"); (2) **arricchimento** che pre-compila i fatti rilevabili — nuova **§ 0 "Direttive di consegna & decisioni"** nel template + regola **enum presentazionale** in `field-extraction.md` (metadata `color`/`icon`/`badge`/`label` → render hint automatico, non una domanda). Attivo standalone **e** delegato da `/prd` (Branch B ora inoltra le preferenze già risolte in Discovery → la skill riconcilia e chiede solo il residuo). **DEGRADE** su Codex/no-TTY: bake dei default DICHIARATI in § 0, mai abort.
13
+
14
+ Resta un *thin orchestrator*, **nessun dual-SSOT** (delivery/placement/varianti non sono in `design-system-protocol.md`). **MINOR** — capability additiva su una skill esistente. **Nessuna nuova chiave `baldart.config.yml`** (rides on `features.has_design_system`) → la schema-change propagation rule NON si applica. Skill versionata `1.0.0 → 1.1.0` (bump `version` + entry nel `CHANGELOG.md` per-skill, stesso edit).
15
+
16
+ ### Added
17
+
18
+ - **`framework/.claude/skills/ds-handoff/references/decision-pass.md`** — il pre-emit Step 5.5: trigger inventory, `AskUserQuestion` consolidata, DEGRADE bake-defaults, riconciliazione in modalità delegata, false-positive guards.
19
+
20
+ ### Changed
21
+
22
+ - **`framework/.claude/skills/ds-handoff/SKILL.md`** — nuovo Step 5.5 nel workflow, Step 6 popola anche § 0, Invocation + Inline fallbacks aggiornati; `version: 1.0.0 → 1.1.0`.
23
+ - **`framework/.claude/skills/ds-handoff/assets/claude-design-handoff-prompt.template.md`** — nuova § 0 "Direttive di consegna & decisioni"; § 7 rimanda a § 0 per il formato export.
24
+ - **`framework/.claude/skills/ds-handoff/references/field-extraction.md`** — regola enum presentazionale (render hint automatico) nel mapping + sezione dedicata.
25
+ - **`framework/.claude/skills/prd/references/ui-design-phase.md`** — Branch B inoltra a `/ds-handoff` le preferenze di consegna/decisione già emerse in Discovery.
26
+ - **`framework/.claude/skills/ds-handoff/CHANGELOG.md`** — entry `1.1.0`.
27
+
8
28
  ## [4.83.0] - 2026-07-01
9
29
 
10
30
  **Versioned root-file primitives — BALDART now generates `AGENTS.md` + `CLAUDE.md` from SOTA skeletons.** Previously `AGENTS.md` was a bulk symlink into the framework payload (not customizable without losing auto-update) and `CLAUDE.md` was not shipped at all. Now both are **generated real files**, produced on every install/update from **versioned skeletons** under `framework/templates/primitives/`.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.83.0
1
+ 4.84.0
@@ -2,6 +2,26 @@
2
2
 
3
3
  Formato: [Keep a Changelog](https://keepachangelog.com/) · [SemVer](https://semver.org/).
4
4
 
5
+ ## 1.1.0 — 2026-07-01
6
+
7
+ - **Decision & preference pass (Step 5.5)** — nuovo `references/decision-pass.md`.
8
+ Chiude l'asse *decisioni* (accanto all'asse *campi* del coverage gate): risolve
9
+ PRIMA di emettere le scelte di design aperte + preferenze di consegna che Claude
10
+ Design altrimenti rimanda all'utente come domande (token `da proporre`, formato
11
+ consegna, scope stati, canvas/placement, appetito varianti). Triggered-not-always-on,
12
+ UNA `AskUserQuestion` consolidata, no-op quando nulla è aperto; per le decisioni
13
+ aperte offre "decido io" vs "fai proporre N opzioni a Claude Design".
14
+ - **Template § 0 "Direttive di consegna & decisioni"** — nuova sezione che porta le
15
+ risposte del pass (placement, formato, stati da consegnare, decisioni aperte,
16
+ varianti) come direttive esplicite; § 7 ora rimanda a § 0 per il formato export.
17
+ - **Enum presentazionale** — `references/field-extraction.md` rileva metadata di
18
+ display (`color`/`icon`/`badge`/`label`) sulle opzioni enum ed emette un render
19
+ hint automatico (es. Categoria con colore → pallino colore per opzione), evitando
20
+ la domanda "come lo rendo?". Non è un `da definire` né una domanda.
21
+ - **DEGRADE** (Codex / no-TTY): il pass fa bake dei default e li DICHIARA in § 0,
22
+ mai abort. **Delegated mode**: riconcilia con le preferenze già risolte da `/prd`
23
+ (Branch B in `ui-design-phase.md` ora le inoltra), chiede solo il residuo.
24
+
5
25
  ## 1.0.0 — 2026-07-01
6
26
 
7
27
  - Baseline: versioning per-skill introdotto al framework v4.82.0.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: ds-handoff
3
3
  effort: medium
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  description: >
6
6
  Produce a FIELD-LEVEL, 1:1, interaction-complete handoff brief for Claude Design
7
7
  — every screen's real fields (label, control type, required, validation, default,
@@ -67,7 +67,9 @@ user input. Level→behavior mapping, parsing contract, and precedence caveats:
67
67
  `/ds-handoff <screens-or-feature>` (standalone) · `/ds-handoff` (ask). When called
68
68
  by `/prd` Step 3.0 Branch B, the caller passes the resolved context (state-file
69
69
  path + feature title/objective/user_flow/personas/screens_in_scope/mockup_analysis
70
- + brand + DS flag) skip the standalone screen-resolution prompt (Step 1's ask).
70
+ + brand + DS flag + any delivery/decision preferences already resolved in Discovery)
71
+ — skip the standalone screen-resolution prompt (Step 1's ask), and reconcile the
72
+ Step 5.5 decision pass against those preferences (ask only the residual).
71
73
 
72
74
  ## Pre-flight
73
75
 
@@ -120,10 +122,23 @@ Each step is a delegation. Read the cited SSOT; do not paraphrase it.
120
122
  user-confirmation (present best-effort, ask the user to fill `da definire`);
121
123
  never hard-abort.
122
124
 
125
+ This gate closes the **field** axis. The **decision** axis is Step 5.5.
126
+
127
+ 5.5. **Decision & preference pass.** DELEGATE —
128
+ [references/decision-pass.md](references/decision-pass.md). Resolve the open
129
+ design choices + delivery/placement preferences that Claude Design would
130
+ otherwise bounce back as questions (the `da proporre` tokens, delivery format,
131
+ state scope, canvas, variation appetite). **Triggered, not always-on** — fires
132
+ only when an item is unresolved; ONE consolidated `AskUserQuestion`; a no-op when
133
+ nothing is open. **DEGRADE** (Codex / no-TTY): bake defaults and DECLARE them in
134
+ § 0, never abort. **Delegated mode:** skip whatever `/prd` already resolved. The
135
+ answers populate the template's § 0.
136
+
123
137
  6. **Fill the mandatory template.** Populate
124
138
  [assets/claude-design-handoff-prompt.template.md](assets/claude-design-handoff-prompt.template.md)
125
- with the reconciled per-screen specs + the top-level sections (brand / design
126
- system / stack / cosa restituirmi). § 5's numeric constraints are the
139
+ with the § 0 delivery/decision directives (from Step 5.5), the reconciled
140
+ per-screen specs + the top-level sections (brand / design system / stack / cosa
141
+ restituirmi). § 5's numeric constraints are the
127
142
  `{{tokens.*}}` placeholders that **cite** `design-system-protocol.md` § Reference
128
143
  Tables — copy values verbatim from the protocol, never invent numbers. Strip
129
144
  empty conditionals.
@@ -152,8 +167,9 @@ Each step is a delegation. Read the cited SSOT; do not paraphrase it.
152
167
 
153
168
  - **No `Workflow` tool needed** — this skill is prose-orchestrated.
154
169
  - **Codex (no subagents):** Step 3's `codebase-architect` degrades to inline Grep
155
- (per `references/field-extraction.md`); the gate degrades BLOCK → user-confirmation
156
- (Step 5). Runs end-to-end.
170
+ (per `references/field-extraction.md`); the Step 5 gate degrades BLOCK →
171
+ user-confirmation; the Step 5.5 decision pass degrades to **bake-defaults**
172
+ declared in § 0 (per `references/decision-pass.md`). Runs end-to-end.
157
173
  - **No LSP / no code-graph:** silent fallback down the retrieval order. Surface a
158
174
  broken layer via `baldart doctor`, never abort here.
159
175
  - **No formal schema in the stack:** the DEGRADE branch — best-effort inventory +
@@ -22,6 +22,23 @@
22
22
 
23
23
  # Feature: {{feature_title}}
24
24
 
25
+ ## 0. Direttive di consegna & decisioni
26
+
27
+ > Queste sono decisioni **già prese** (o esplicitamente delegate a te). Non
28
+ > richiedermele: seguile, oppure — dove indicato "proponi N opzioni" — proponi le
29
+ > alternative con i loro trade-off invece di sceglierne una a caso.
30
+
31
+ - **Dove collocarlo**: {{delivery.target_canvas}} <!-- es. "Nuovo canvas «Hub fornitore desktop/tablet», NON dentro il master-detail Fornitori esistente" -->
32
+ - **Formato di consegna**: {{delivery.output_delivery}} <!-- "1 artboard per stato (PNG ≥2x)" | "prototipo interattivo navigabile" | "entrambi" -->
33
+ - **Stati da consegnare**: {{delivery.states_to_deliver}} <!-- lista esplicita — consegna ESATTAMENTE questi, non chiedermi di deselezionare -->
34
+ {{#if delivery.open_decisions}}
35
+ - **Decisioni di design aperte**:
36
+ {{#each delivery.open_decisions}}
37
+ - **{{this.topic}}**: {{this.directive}} <!-- valore deciso, OPPURE "proponi {{this.n}} opzioni con trade-off" -->
38
+ {{/each}}
39
+ {{/if}}
40
+ - **Varianti**: {{delivery.variations}} <!-- "nessuna oltre le decisioni sopra" | assi richiesti (es. layout griglia, densità gruppi, posizione action bar) -->
41
+
25
42
  ## 1. Obiettivo
26
43
 
27
44
  {{feature_objective_one_sentence}}
@@ -172,9 +189,13 @@
172
189
 
173
190
  ## 7. Cosa restituirmi
174
191
 
175
- Per ogni schermata elencata in § 3:
192
+ Per ogni schermata elencata in § 3, nel **formato di consegna deciso in § 0**
193
+ ({{delivery.output_delivery}}):
176
194
 
177
- 1. **PNG export** ad alta risoluzione (≥ 2x) di OGNI stato richiesto (es. `dettaglio-fornitore__loading.png`, `dettaglio-fornitore__populated.png`).
195
+ 1. **Export** ad alta risoluzione (≥ 2x) di OGNI stato in **§ 0 → Stati da
196
+ consegnare** (es. `dettaglio-fornitore__loading.png`,
197
+ `dettaglio-fornitore__populated.png`). Se § 0 chiede un prototipo interattivo,
198
+ consegna gli stati come schermi navigabili invece che come PNG separati.
178
199
  2. {{output_format_preference_block}} <!-- "Codice HTML/CSS in un file unico" | "Codice React (.tsx) con import Tailwind" | "Link Figma alla frame" -->
179
200
  3. **Mappa di tracciabilità campo→funzione** — per OGNI campo della field inventory,
180
201
  conferma che sia presente e col controllo/mode indicati. Se un campo di § 3 manca
@@ -0,0 +1,94 @@
1
+ # Decision & preference pass — resolve the open choices BEFORE emitting
2
+
3
+ `ds-handoff` Step 5.5. Runs **after** the coverage gate (Step 5, which verifies the
4
+ *fields*) and **before** filling the template (Step 6). Where the coverage gate
5
+ closes the *data-correctness* axis, this pass closes the **decision axis**: the open
6
+ design choices, delivery preferences and workspace directives that — if left
7
+ implicit — Claude Design bounces back to the user as questions.
8
+
9
+ The failure this prevents: a prompt that says *"pattern editing per-sede, da
10
+ proporre"* forces Claude Design to STOP and ask which pattern; a prompt that lists
11
+ states but never says "deliver exactly these" invites a "deselect what you don't
12
+ need" round-trip; an enum with a colour but no render directive gets a "how do I
13
+ show the colour?" question. Every one of those is a decision BALDART can make (or
14
+ frame) up front.
15
+
16
+ **Same discipline as the coverage gate:** decision-**triggered**, not always-on —
17
+ it fires ONLY when there is an unresolved item; ONE consolidated `AskUserQuestion`;
18
+ never assume a default silently. If nothing is unresolved, this step is a **no-op**
19
+ and you proceed straight to Step 6.
20
+
21
+ ## Trigger inventory — what makes the pass necessary
22
+
23
+ Scan the reconciled per-screen specs (Step 4 output: regions, actions, states,
24
+ list behaviour) plus the delegated/standalone context. An item is "unresolved" when:
25
+
26
+ | Item | Unresolved when… | Detection |
27
+ |---|---|---|
28
+ | **Open design decision** | an affordance/layout/pattern is explicitly left open | literal token `da proporre` / `da decidere` / `(… inline/pannello/rotta, da proporre)` / `TBD` / `?` in a region/action/state cell |
29
+ | **Delivery format** | not stated in context | no `output_delivery` in the delegated context / standalone args |
30
+ | **State scope** | states enumerated but not confirmed as the deliverable set | states present but no explicit "deliver these" directive |
31
+ | **Placement / canvas** | the Claude Design workspace target is unknown | no `target_canvas` in context |
32
+ | **Variation appetite** | the user's want for alternatives beyond the open decisions is unknown | not stated in context |
33
+
34
+ If EVERY row is already resolved (all decided in the source / passed by `/prd`),
35
+ **do not ask** — skip to Step 6.
36
+
37
+ ## The consolidated AskUserQuestion (interactive, human present)
38
+
39
+ Raise **exactly ONE** `AskUserQuestion` covering only the unresolved rows. Suggested
40
+ questions (drop any that is already resolved; `multiSelect` where noted):
41
+
42
+ 1. **Per each open design decision** — offer two shapes of resolution:
43
+ - *"Decido io"* → the user picks the concrete option (list the plausible ones:
44
+ e.g. inline / side-panel / dedicated route). The chosen value goes into §0 as a
45
+ firm directive.
46
+ - *"Fai proporre a Claude Design"* → frame it in the prompt as *"proponi N opzioni
47
+ per X con trade-off"*. This is legitimate — Claude Design is a design tool and
48
+ proposing is its job; the point is to make the ASK **intentional** in the prompt
49
+ instead of an accidental blocker.
50
+ 2. **Formato di consegna** — `artboard-per-stato (PNG ≥2x)` (default) | `prototipo
51
+ interattivo navigabile` | both.
52
+ 3. **Stati da consegnare** (`multiSelect`) — pre-checked with the full detected list;
53
+ the user unchecks any out of scope. The confirmed set becomes `states_to_deliver`.
54
+ 4. **Placement / canvas** — `nuovo canvas dedicato «<feature>»` (default) | `dentro
55
+ un canvas esistente` (ask which).
56
+ 5. **Varianti oltre le decisioni aperte** — `nessuna` (default) | pick axes (grid
57
+ layout, densità gruppi, posizione action bar, …).
58
+
59
+ Only after the user answers do you populate §0 and proceed to Step 6. Consistent with
60
+ always-ask-never-assume and "no silent deferral".
61
+
62
+ ## DEGRADE (graceful — Codex / no-TTY / unattended)
63
+
64
+ When no interactive prompt is possible (Codex without subagents, no-TTY, an
65
+ autonomous run), do **not** hard-abort and do **not** ask. Instead **bake the
66
+ defaults** and **declare them explicitly** in §0 so the choice is visible, not
67
+ silent:
68
+
69
+ - Open decisions → framed as *"proponi 2 opzioni per X"* (let CD propose, since we
70
+ can't ask the user).
71
+ - Delivery → `artboard-per-stato (PNG ≥2x)`.
72
+ - States → deliver the full detected list.
73
+ - Placement → `nuovo canvas dedicato`.
74
+ - Variations → `nessuna`.
75
+
76
+ The prompt still ships, with an honest §0 the user can review — never an abort.
77
+
78
+ ## Delegated-mode reconciliation (called from /prd)
79
+
80
+ When invoked from `/prd` Step 3.0 Branch B, the caller may already have resolved some
81
+ of these during Discovery (a delivery preference, a placement, an explicit design
82
+ decision). The passed context is authoritative: **skip every already-resolved row**
83
+ and ask only the residual. Never re-ask what `/prd` already knows. If the context
84
+ resolves everything, the pass is a no-op even in delegated mode.
85
+
86
+ ## False-positive guards (do NOT treat as an open decision)
87
+
88
+ - **Descriptive prose that isn't a bivio** — a region note like "header con nome e
89
+ stato" is a spec, not a choice. Only a literal open-choice token (see the trigger
90
+ table) counts.
91
+ - **Fields** — those are the coverage gate's job (Step 5), not this pass. A `da
92
+ definire` cell is a *data* gap, not a *decision*; do not surface it here.
93
+ - **Already-decided affordances** — an action with a concrete effect/destination is
94
+ resolved; don't ask about it.
@@ -44,7 +44,7 @@ Anything you cannot ground in code is the **literal `da definire`** — never a
44
44
  | **Required** | `sì` unless `.optional()` / `.nullish()` / `?` / `.partial()`. | `da definire` |
45
45
  | **Validazione/Vincoli** | `.min()`/`.max()`/`.length()`/`.regex()`/`.email()`/`.url()`/`.int()`/`.positive()`/refinements. | `—` if none |
46
46
  | **Default** | `.default(x)` / a form `defaultValues` entry. | `—` if none |
47
- | **Opzioni / sorgente enum** | `z.enum([...])` / `z.nativeEnum` literals verbatim; a `z.string()` whose options come from a runtime query → `"query runtime — da definire"`. | `—` / `da definire` |
47
+ | **Opzioni / sorgente enum** | `z.enum([...])` / `z.nativeEnum` literals verbatim; a `z.string()` whose options come from a runtime query → `"query runtime — da definire"`. When the option source carries **presentational metadata**, add the render hint (see below). | `—` / `da definire` |
48
48
  | **Helper text** | JSDoc on the field; the i18n `context` for the key; an existing form description. | `da definire` |
49
49
  | **Mode** | `editable` by default; `readonly` for server-set / computed fields (see below). | `editable` |
50
50
  | **Card/gruppo** | From `mockup_analysis.screens[].layout` when present, else the reconciliation decision (Step 4). | `da definire` |
@@ -57,6 +57,7 @@ component binding, a form control already in code) over the heuristic when prese
57
57
  | Schema / type shape | Control |
58
58
  |---|---|
59
59
  | `z.enum([...])` / `z.nativeEnum` / union of string literals | `select` (or `radio` for ≤ 3 options / `segmented` per project convention) |
60
+ | enum whose option source carries **presentational metadata** (`color` / `icon` / `badge` / `label`) — a lookup table, a `const` map, a DB category with a colour | `select` **+ a render hint** (see "Presentational enums" below) |
60
61
  | `z.boolean()` | `toggle` (or `checkbox`) |
61
62
  | `z.string()` short (no/small `.max`) | `text input` |
62
63
  | `z.string()` long (`.max` ≥ ~200, or named `notes`/`description`/`body`) | `textarea` |
@@ -69,6 +70,25 @@ component binding, a form control already in code) over the heuristic when prese
69
70
  | `z.array(z.string())` from a known set | `multi-select` |
70
71
  | `z.object(...)` nested | a sub-group / sub-card |
71
72
 
73
+ ## Presentational enums (pre-empt the "how do I render it?" question)
74
+
75
+ When an enum's options are not bare strings but carry **display metadata** — a
76
+ category with a `color`, a status with an `icon`, an option with a human `label`
77
+ distinct from its value — capturing the values alone leaves Claude Design to guess
78
+ *how* to render them, which becomes a round-trip question. Instead, **detect the
79
+ extra fields and emit a render hint** in the Opzioni cell, so the directive is
80
+ explicit:
81
+
82
+ - Colour per option → `"<EnumName> (name + color) → pallino/badge colore per opzione; colore = .color"`.
83
+ - Icon per option → `"<EnumName> (name + icon) → icona per opzione; icona = .icon"`.
84
+ - Human label ≠ value → give both: `"value → «Label»"` per option.
85
+
86
+ Ground the metadata the same way as the enum itself (the lookup table / `const` map
87
+ / schema). If the option list is a runtime query, still note the presentational field
88
+ if the row shape exposes it (`"query runtime — ogni riga ha { name, color }"`). This
89
+ is a documented hint the extraction step fills automatically — it is **not** a `da
90
+ definire` and it is **not** a user question.
91
+
72
92
  ## Readonly detection
73
93
 
74
94
  Mark a field **readonly** (static text, no editable control) when it is not
@@ -46,10 +46,15 @@ delegate-or-else-inline contract as `/prd` → `/ds-new`.)
46
46
  per-screen routing table");
47
47
  - `mockup_analysis` from `## UI Design` if present (the skill reads its
48
48
  `layout / component_props / states / responsive` as input);
49
- - the `features.has_design_system` flag (the skill omits § 5 when `false`).
50
-
51
- `/ds-handoff` runs field extraction + the coverage gate + the mandatory template
52
- and returns the **rendered prompt** plus the **`field-inventory.md` path**.
49
+ - the `features.has_design_system` flag (the skill omits § 5 when `false`);
50
+ - **any delivery/decision preferences already surfaced in Discovery** (output
51
+ format, target canvas, a design decision the user already made) `/ds-handoff`
52
+ runs a **decision pass** (its Step 5.5) before emitting, and reconciles against
53
+ what you pass so it asks only the residual, never re-asking the known.
54
+
55
+ `/ds-handoff` runs field extraction + the coverage gate + the decision pass + the
56
+ mandatory template and returns the **rendered prompt** plus the
57
+ **`field-inventory.md` path**.
53
58
 
54
59
  **Graceful fallback** — if `/ds-handoff` is unavailable (Codex without it linked,
55
60
  or an older install): render a **coarse** brief inline from `screens_in_scope[]`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.83.0",
3
+ "version": "4.84.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"