baldart 3.27.1 → 3.28.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/CHANGELOG.md CHANGED
@@ -5,6 +5,50 @@ 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
+ ## [3.28.1] - 2026-05-28
9
+
10
+ Patch su tre drift segnalati dal curator dopo v3.28.0 install in `mayo`:
11
+ (1) `--yes` non si propaga da `update --reset` al child `baldart add`,
12
+ (2) errore "Configuring alias is not permitted without enabling allowUnsafeAlias" stampato come install-failed mentre l'install era OK,
13
+ (3) due template `ui-guidelines.template.md` + `brand-guidelines.md` lasciati untracked senza istruzioni chiare all'utente. Tutti e tre cosmetici/UX, nessuno affecta la correctness del framework installato — ma confondono l'utente durante il post-install.
14
+
15
+ ### Fixed — `baldart add` honors `--yes` from parent caller
16
+
17
+ - **[src/commands/add.js](src/commands/add.js)** + **[src/commands/update.js:237](src/commands/update.js)**: `add(repo, options)` ora legge `options.yes` e auto-conferma i prompt non-distruttivi (`Install framework?`, `Configure git aliases?`, `Configure project context now?`). Il prompt distruttivo `Remove and reinstall?` resta interattivo anche con `--yes` (safety). `update --reset` ora invoca correttamente `addCmd(undefined, { yes: true })` — prima passava `{ yes: true }` come **primo argomento** (cioè `repo`), facendo `options` undefined e ogni prompt scattava.
18
+
19
+ ### Fixed — Git alias config failure non più mascherato da install-failure
20
+
21
+ - **[src/commands/add.js](src/commands/add.js)**: la configurazione degli alias `fw-version`/`fw-update`/`fw-push` passa da `git.git.addConfig()` (simple-git, che rifiuta i bang-alias senza `allowUnsafeAlias`) a `spawnSync('git', ['config', key, value])` diretto. Il bypass del check simple-git è esplicito qui: l'utente sta opt-in agli alias durante l'install. Failure isolato per alias (non bubble-up al catch globale), reported come WARNING se non-zero count, install continua. Il messaggio "✗ Installation failed: Configuring alias is not permitted…" non appare più.
22
+
23
+ ### Fixed — Template editable post-install: istruzioni chiare
24
+
25
+ - **[src/commands/add.js](src/commands/add.js)** NEXT STEPS box: i due template `docs/references/ui-guidelines.template.md` e `docs/references/brand-guidelines.md`, copiati incondizionatamente durante `copyCustomizableFiles()`, ora sono elencati esplicitamente con cosa farne (rename / edit / delete) e con il punto chiave: "Commit them to track your project's design language, or add them to .gitignore if you don't need them." Evita la confusione del curator durante v3.28.0 install ("non chiari se debbano essere scelti/scartati dall'utente o committati. Non c'è prompt che lo chieda").
26
+
27
+ ## [3.28.0] - 2026-05-28
28
+
29
+ Tre additions indipendenti accumulate nel working tree e pronte per il rilascio: convenzione testuale per le dipendenze MCP, supporto `.zip` per il mockup intake del PRD, e nuovo hook `capture-detect` come parte del proactive mode dello skill `/capture` (registrazione opt-in, non auto-attivata). Tre temi distinti ma raggruppati in un'unica release di accumulo perché tutti additive e zero-schema-change.
30
+
31
+ ### Added — Convenzione MCP integration
32
+
33
+ - **[framework/docs/MCP-INTEGRATION.md](framework/docs/MCP-INTEGRATION.md)**: nuovo documento centralizzato. Spiega quando un agent/skill deve appoggiarsi a un MCP server, fornisce un catalogo di MCP raccomandati per i casi d'uso comuni (doc-rag, playwright, firestore/db, LSP, …), e definisce la convenzione testuale "MCP dependencies" per dichiarare le dipendenze nel body dell'agent/skill. Zero nuove chiavi config in `baldart.config.yml` — la convenzione resta testuale finché una skill concreta non dovrà gate-arne il comportamento (regola di schema-change propagation: niente layer drift).
34
+ - **[framework/.claude/agents/codebase-architect.md](framework/.claude/agents/codebase-architect.md)**: aggiunta sezione `## MCP dependencies` con classificazione Required (`doc-rag` come primo step dell'Investigation Protocol) vs Optional (LSP find-references, DB MCP per inspect runtime). Documentato il degrade path quando l'MCP non è disponibile.
35
+ - **[framework/.claude/skills/bug/SKILL.md](framework/.claude/skills/bug/SKILL.md)**: aggiunta sezione `## MCP dependencies` con Required (`playwright` per Phase 1 reproduction di UI/Client bug — senza è impossibile catturare stato deterministico) e Optional (`doc-rag` per known patterns, DB MCP per Data bugs, `codebase-architect` agent).
36
+
37
+ ### Added — PRD mockup intake da archivio `.zip`
38
+
39
+ - **[framework/.claude/skills/prd/SKILL.md](framework/.claude/skills/prd/SKILL.md)** Step 1.6: nuovo formato `local-archive` accettato accanto a `chat-images` / `local-paths` / `mixed`. Caso d'uso: export "Download as .zip" da Claude Design (o qualsiasi altro tool che produce bundle di mockup) già scaricato sul disco dell'utente.
40
+ - **[framework/.claude/skills/prd/references/discovery-phase.md](framework/.claude/skills/prd/references/discovery-phase.md)** § Mockup Intake: Step 1.6.4b descrive l'intero flow per `.zip` — `unzip` in scratch dir `mockups/_archive/`, enumerazione candidati visivi, scoring di rilevanza contro lo scope del Kickoff, selezione auto-proposta, STOP per conferma, materializzazione del sottoinsieme confermato in `${paths.prd_dir}/<slug>/mockups/`. Evita di copiare PNG irrilevanti nell'asset directory definitiva.
41
+ - **[framework/.claude/skills/prd/assets/state-template.md](framework/.claude/skills/prd/assets/state-template.md)**: aggiornato `mockups.format` enum per includere `local-archive`.
42
+
43
+ ### Added — Hook `capture-detect` (proactive mode, opt-in)
44
+
45
+ - **[framework/.claude/hooks/capture-detect.sh](framework/.claude/hooks/capture-detect.sh)**: nuovo Stop hook che drop una candidate JSON in `.claude/capture-queue/` quando rileva ragionamento cross-document nella sessione appena chiusa. La distillazione vera in synthesis page wiki resta sempre una human-approved manual step via lo skill `/capture`. Failure-isolated (exit 0 sempre, non blocca lo Stop event).
46
+ - **Registrazione opt-in (NOT auto-attivata)**: la entry corrispondente in [src/utils/hooks.js](src/utils/hooks.js) resta commentata (linee 90-97). Lo skill `/capture` funziona già in modalità manual senza il hook; il proactive mode è una feature opzionale. Per attivarlo nel proprio consumer: scommentare la entry e re-installare via `npx baldart update`. Una futura release potrà rendere il proactive il default.
47
+
48
+ ### Added — Smoke test del hooks registry
49
+
50
+ - **[scripts/test-hooks.sh](scripts/test-hooks.sh)**: nuovo smoke test per `src/utils/hooks.js` (multi-hook registry introdotto v3.18.0). Verifica register/unregister/isRegistered/merge idempotente con fixture in tmpdir. Dev tooling, non user-visible.
51
+
8
52
  ## [3.27.1] - 2026-05-28
9
53
 
10
54
  Patch follow-up alla v3.27.0 dopo l'incidente reale in `mayo`: l'utente aveva CLI globale v3.24.0 e ha eseguito `/baldart-update` per aggiornarsi a v3.27.0. La skill ha rilanciato `npx baldart update`, che ha aggiornato il framework payload da v3.24 a v3.27, ma `update.js` in esecuzione era il binario v3.24.0 — quello che precede sia il meccanismo di auto-relaunch (introdotto v3.26.0) sia la logica di symlink-indirection (v3.27.0). Risultato: i 6 agent overlay-merged sono stati rigenerati con la **vecchia logica** (file regolari direttamente in `.claude/agents/`), e quindi il fix v3.27.0 NON si è attivato — `npx baldart doctor` ha riportato "tutto healthy" ma in realtà gli agent erano ancora invisibili a Claude Code (bug #20931). Chicken-and-egg: il CLI vecchio non sa rilanciare il nuovo, il nuovo non è ancora in esecuzione.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.27.1
1
+ 3.28.1
@@ -37,6 +37,17 @@ This codebase follows strict protocols defined in AGENTS.md. Key architectural r
37
37
  - `/docs/references/project-status.md` - Current system state and active work
38
38
  - `agents/coding-standards.md` - Terminology and coding conventions
39
39
 
40
+ ## MCP dependencies
41
+
42
+ See [framework/docs/MCP-INTEGRATION.md](../../docs/MCP-INTEGRATION.md) for the BALDART MCP integration contract and the rationale behind this section.
43
+
44
+ **Required** (this agent's primary investigation protocol assumes them; degraded operation only):
45
+ - `mcp__doc-rag__search_docs` — semantic + knowledge-graph search across project docs. This is the **first** call in the Investigation Protocol; without it the agent falls back to broad `rg` sweeps that blow the token budget and miss canonical sources. If the MCP is unavailable the agent must announce the degrade explicitly and switch to targeted `rg` over `docs/`, `backlog/`, and `.claude/agents/` (see § Investigation Protocol step 1).
46
+
47
+ **Optional** (the agent benefits if present, has a documented fallback):
48
+ - LSP find-references / go-to-definition (whichever LSP MCP / plugin is wired by [features.has_lsp_layer](../../templates/baldart.config.template.yml)) — preferred over `rg` for symbol queries (cap: 3 LSP calls per task, then escalate to direct file reads). Fallback: silent degrade to Grep, per [code-search-protocol.md](../../agents/code-search-protocol.md).
49
+ - `mcp__plugin_firebase_firebase__firestore_*` (or equivalent DB MCP) — only when the architectural analysis needs to inspect runtime DB state (rare for an architect agent). Fallback: read schema docs in `${paths.references_dir}` and rely on declared structure.
50
+
40
51
  ## Linking Protocol Consumption (MUST)
41
52
 
42
53
  You consume Linking Protocol v1 in read-only mode to find the right facts faster before
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # capture-detect.sh — BALDART proactive capture hook (event: Stop)
4
+ #
5
+ # Runs at the end of every Claude Code session. When the just-finished
6
+ # session contains cross-document reasoning (the user has been weaving
7
+ # together facts from multiple docs/references files), this hook drops a
8
+ # *candidate* file into `.claude/capture-queue/` so the next `/capture`
9
+ # invocation can surface it and offer to distill the synthesis into a
10
+ # durable wiki page.
11
+ #
12
+ # This hook NEVER spawns Claude itself — it only writes a small JSON
13
+ # candidate. The actual synthesis is always a human-approved manual step
14
+ # via the `capture` skill.
15
+ #
16
+ # Stdin: Claude Code passes a JSON envelope; we read `transcript_path`,
17
+ # `session_id`, `cwd` (best-effort — falls back if jq is unavailable).
18
+ #
19
+ # Exit: always 0. Failure isolation — a non-zero exit on a Stop hook can
20
+ # be ignored by the runtime, but as a matter of hygiene we never
21
+ # propagate errors out of an instrumentation hook.
22
+
23
+ set -u
24
+ exec 2>/dev/null # silence stderr; we are not user-visible
25
+
26
+ # --- read envelope --------------------------------------------------------
27
+
28
+ INPUT=""
29
+ if [ ! -t 0 ]; then
30
+ INPUT="$(cat)"
31
+ fi
32
+
33
+ # Try jq first, fall back to grep/sed extraction.
34
+ get_field() {
35
+ local field="$1"
36
+ if command -v jq >/dev/null 2>&1; then
37
+ printf '%s' "$INPUT" | jq -r ".$field // empty" 2>/dev/null
38
+ else
39
+ printf '%s' "$INPUT" | sed -n "s/.*\"$field\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" | head -1
40
+ fi
41
+ }
42
+
43
+ TRANSCRIPT_PATH="$(get_field transcript_path)"
44
+ SESSION_ID="$(get_field session_id)"
45
+ CWD_FROM_ENV="$(get_field cwd)"
46
+ CWD="${CWD_FROM_ENV:-$PWD}"
47
+
48
+ [ -n "$TRANSCRIPT_PATH" ] || exit 0
49
+ [ -f "$TRANSCRIPT_PATH" ] || exit 0
50
+
51
+ cd "$CWD" 2>/dev/null || exit 0
52
+
53
+ # --- gate on features.has_wiki_overlay -----------------------------------
54
+
55
+ CONFIG="baldart.config.yml"
56
+ [ -f "$CONFIG" ] || exit 0
57
+ # Coarse check: look for `has_wiki_overlay: true` (whitespace-tolerant).
58
+ if ! grep -E '^\s*has_wiki_overlay\s*:\s*true\b' "$CONFIG" >/dev/null 2>&1; then
59
+ exit 0
60
+ fi
61
+
62
+ # --- gates: kill switch + anti-spam --------------------------------------
63
+
64
+ QUEUE_DIR=".claude/capture-queue"
65
+ mkdir -p "$QUEUE_DIR" || exit 0
66
+
67
+ [ -f "$QUEUE_DIR/.disabled" ] && exit 0
68
+
69
+ # Anti-spam: refuse when ≥10 unprocessed candidates already queued.
70
+ EXISTING="$(find "$QUEUE_DIR" -maxdepth 1 -type f -name '*.json' 2>/dev/null | wc -l | tr -d ' ')"
71
+ [ "${EXISTING:-0}" -ge 10 ] && exit 0
72
+
73
+ # --- heuristic: is this session worth flagging? --------------------------
74
+ #
75
+ # We treat "≥3 distinct docs/references-style paths mentioned across the
76
+ # session" as a weak signal of cross-document reasoning. False positives
77
+ # are acceptable here — the user reviews every candidate in /capture and
78
+ # can reject. False negatives are also fine — the user can always invoke
79
+ # /capture manually.
80
+
81
+ REFS="$(grep -ohE '(\./|/|\b)((docs|wiki|references|backlog|prd)/[A-Za-z0-9._/-]+\.(md|yml|yaml|json))' "$TRANSCRIPT_PATH" 2>/dev/null \
82
+ | sort -u | head -10)"
83
+
84
+ REF_COUNT="$(printf '%s\n' "$REFS" | grep -c . || true)"
85
+ [ "${REF_COUNT:-0}" -lt 3 ] && exit 0
86
+
87
+ # --- write candidate ------------------------------------------------------
88
+
89
+ TS_FILE="$(date -u +%Y%m%dT%H%M%SZ)"
90
+ TS_HUMAN="$(date -u +'%Y-%m-%d %H:%M UTC')"
91
+ OUT="$QUEUE_DIR/${TS_FILE}-${SESSION_ID:-unknown}.json"
92
+
93
+ # JSON-escape with awk (no jq required for emit either).
94
+ escape_json() {
95
+ printf '%s' "$1" | awk 'BEGIN{ORS=""} {gsub(/\\/,"\\\\"); gsub(/"/,"\\\""); gsub(/\r/,""); gsub(/\n/,"\\n"); print}'
96
+ }
97
+
98
+ REFS_JSON="["
99
+ first=1
100
+ while IFS= read -r r; do
101
+ [ -z "$r" ] && continue
102
+ if [ $first -eq 1 ]; then first=0; else REFS_JSON="$REFS_JSON,"; fi
103
+ REFS_JSON="$REFS_JSON\"$(escape_json "$r")\""
104
+ done <<EOF
105
+ $REFS
106
+ EOF
107
+ REFS_JSON="$REFS_JSON]"
108
+
109
+ cat > "$OUT" <<JSON
110
+ {
111
+ "trigger": "cross_doc_refs",
112
+ "detected_at": "$TS_HUMAN",
113
+ "session_id": "$(escape_json "${SESSION_ID:-unknown}")",
114
+ "transcript_path": "$(escape_json "$TRANSCRIPT_PATH")",
115
+ "refs_mentioned": $REFS_JSON,
116
+ "excerpt": "Session referenced ${REF_COUNT} distinct doc paths — possible cross-document synthesis worth capturing.",
117
+ "hint": "Run /capture to review this candidate."
118
+ }
119
+ JSON
120
+
121
+ exit 0
@@ -21,6 +21,18 @@ Argument: optional bug description (e.g., `/bug feature X is not saving`).
21
21
  **Overlay:** loads `.baldart/overlays/bug.md` if present — project-specific debug entry points (e.g. SWR debug switches, env summary helpers, error-code modules). The base skill stays generic; project-specific code paths live in the overlay.
22
22
  **On missing/empty keys:** ask the user; do not assume defaults. See `framework/agents/project-context.md` § 3.
23
23
 
24
+ ## MCP dependencies
25
+
26
+ See [framework/docs/MCP-INTEGRATION.md](../../../docs/MCP-INTEGRATION.md) for the BALDART MCP integration contract and the rationale behind this section.
27
+
28
+ **Required** (skill cannot complete its task without these MCPs for the relevant bug class):
29
+ - `mcp__playwright__browser_*` (`browser_navigate`, `browser_take_screenshot`, `browser_console_messages`, `browser_network_requests`, `browser_evaluate`) — Phase 1 reproduction for **UI/Client** bugs. Without it the skill cannot capture deterministic state and Phase 1 degrades to "ask the user to reproduce manually and paste console logs". Phase 2's client-side `window.fetch` interception is impossible without `browser_evaluate`.
30
+
31
+ **Optional** (the skill benefits if present, has a documented fallback):
32
+ - `mcp__doc-rag__search_docs` — Phase 0 lookup for known patterns and error codes. Fallback: targeted `rg` over the project's error-code module (path listed in `.baldart/overlays/bug.md`) and `docs/wiki/`.
33
+ - `mcp__plugin_firebase_firebase__firestore_*` (or the project's DB MCP, when `stack.database.primary` is set) — Phase 1 inspection of runtime data state for **Data** bugs. Fallback: ask the user for a document export, or read the relevant code path and infer.
34
+ - `codebase-architect` agent (always available, listed for completeness) — Phase 0 code-path mapping. Not an MCP per se but is treated as a required dependency by this skill.
35
+
24
36
  ## ANTI-PATTERNS (NEVER DO)
25
37
 
26
38
  - NEVER change code before reproducing the bug
@@ -92,8 +92,17 @@ message. You ask questions, wait for answers, and iterate.
92
92
  structure and `assets/card-template.yml` for child structure.
93
93
  16. **Mockup Intake (MANDATORY).** Subito dopo Kickoff (Step 1) e prima di entrare in
94
94
  Discovery (Step 2), esegui Step 1.6 — chiedi all'utente se ha mockup a disposizione.
95
- Se **sì**: chiedi formato (immagini in chat / path locali), **STOP**, attendi. Sull'arrivo:
96
- copia i path locali in `${paths.prd_dir}/<slug>/mockups/`, analizza in dettaglio (vedi
95
+ Se **sì**: chiedi formato (immagini in chat / path locali singoli file **o
96
+ archivi `.zip`** / misti), **STOP**, attendi. Sull'arrivo:
97
+ - **chat-images** / file singoli in **local-paths**: copia in `${paths.prd_dir}/<slug>/mockups/`,
98
+ passa subito all'analisi.
99
+ - **`.zip` in local-paths** (es. export "Download as .zip" da Claude Design già
100
+ sul disco): esegui Step 1.6.4b — `unzip` in scratch dir sotto `mockups/_archive/`,
101
+ enumera i candidati visivi, calcola uno score di rilevanza contro lo scope
102
+ del Kickoff, presenta la selezione auto-proposta, **STOP**, attendi conferma,
103
+ poi materializza solo il sottoinsieme confermato in `${paths.prd_dir}/<slug>/mockups/`.
104
+
105
+ Quindi analizza in dettaglio (vedi
97
106
  [discovery-phase.md](references/discovery-phase.md) § "Mockup analysis schema"), popola
98
107
  `## UI Design` nello state, poi entra in Discovery. Se **no**: marca
99
108
  `mockups.status: none` e procedi col flow standard. Il decision tree di Step 3 (UI Design)
@@ -74,11 +74,18 @@ Scenarios: pending
74
74
 
75
75
  ## UI Design
76
76
 
77
- mockups.status: pending # none | requested | provided | partial
78
- mockups.format: pending # chat-images | local-paths | mixed
79
- mockups.original_paths: [] # user-provided paths or chat://image-N
77
+ mockups.status: pending # none | requested | provided | partial | pending_external
78
+ mockups.format: pending # chat-images | local-paths | local-archive | mixed
79
+ mockups.original_paths: [] # user-provided paths, chat://image-N, or archive://<rel-path>
80
80
  mockups.canonical_paths: [] # mockups/<file> after copy
81
81
 
82
+ mockups.archive: # populated only when format includes local-archive
83
+ local_zip_path: pending # abs path of the .zip the user gave us
84
+ kind: pending # zip
85
+ extracted_dir: pending # abs path of _archive/extracted/
86
+ truncated: false # true when candidate list capped at 200
87
+ candidates: [] # see discovery-phase.md § 1.6.4b step b-c
88
+
82
89
  mockup_analysis.screens: [] # see discovery-phase.md § Mockup analysis schema
83
90
  mockup_analysis.user_flow: []
84
91
  mockup_analysis.design_system_alignment:
@@ -172,9 +172,12 @@ Append this follow-up to the SAME message:
172
172
  Perfetto. In che forma me li passi?
173
173
 
174
174
  - **Immagini in chat** — incollale direttamente nel prossimo messaggio.
175
- - **Path locali** — incolla i percorsi (assoluti o relativi al repo) e li copio
176
- in `${paths.prd_dir}/<slug>/mockups/`.
177
- - **Misti** entrambe le cose.
175
+ - **Path locali** — incolla i percorsi (assoluti o relativi al repo). Funzionano:
176
+ - file singoli (PNG, HTML, SVG, …) → li copio in `${paths.prd_dir}/<slug>/mockups/`.
177
+ - **archivi `.zip`** (es. export "Download as .zip" da Claude Design già
178
+ scaricato sul tuo disco) → lo unzippo io, analizzo TUTTI i mockup dentro
179
+ e seleziono automaticamente quelli rilevanti per questa feature.
180
+ - **Misti** — combinazioni delle modalità sopra.
178
181
  ```
179
182
 
180
183
  - Update state file `## UI Design`: `mockups.status: requested`, `mockups.format: pending`.
@@ -184,19 +187,170 @@ Perfetto. In che forma me li passi?
184
187
 
185
188
  When the user replies with the mockups:
186
189
 
187
- 1. **Detect format** and update `mockups.format` ∈ {`chat-images`, `local-paths`, `mixed`}.
190
+ 1. **Detect format** and update `mockups.format` ∈ {`chat-images`, `local-paths`, `local-archive`, `mixed`}.
191
+ - `local-archive` applies when at least one of the provided local paths is a
192
+ `.zip` (case-insensitive) — also if mixed with other regular files.
188
193
  2. **For each local path provided:**
189
194
  - Resolve to absolute path. If file does not exist: ask the user to confirm/correct
190
195
  (do not silently skip).
191
- - Ensure `${paths.prd_dir}/<slug>/mockups/` exists (create if missing).
192
- - Copy the file into that directory, preserving filename. On collision (file with
193
- same name already there): append numeric suffix (`<name>-2.png`).
196
+ - **If the path is a `.zip`** (extension match OR `file <path>` reports a Zip
197
+ archive): route it to Step 1.6.4b and DO NOT copy the zip itself into
198
+ `${paths.prd_dir}/<slug>/mockups/`. Only the user-confirmed subset extracted
199
+ from it ends up there.
200
+ - **Otherwise** (regular mockup file): ensure `${paths.prd_dir}/<slug>/mockups/`
201
+ exists (create if missing), then copy the file into that directory,
202
+ preserving filename. On collision (file with same name already there):
203
+ append numeric suffix (`<name>-2.png`).
194
204
  - Record both paths in state: `mockups.original_paths[]` and `mockups.canonical_paths[]`.
195
205
  3. **For chat images:** record in state `mockups.original_paths[]` as `chat://image-N`
196
206
  (the images remain in the conversation context window).
197
- 4. Update `mockups.status: provided` (or `partial` only if the user explicitly says
207
+ 4. **For zip archives:** execute Step 1.6.4b BEFORE marking `status: provided`. The
208
+ archive flow has its own scan + selection + confirmation gate; only the
209
+ user-confirmed subset is copied into `${paths.prd_dir}/<slug>/mockups/`.
210
+ 5. Update `mockups.status: provided` (or `partial` only if the user explicitly says
198
211
  "ho solo questi 2 ma servono anche altri").
199
212
 
213
+ ### 1.6.4b — Archive ingestion & relevance selection (when `mockups.format` includes `local-archive`)
214
+
215
+ Triggered when the user hands a local `.zip` path (typically a Claude Design
216
+ "Download as .zip" export already on disk). The flow scans every mockup inside,
217
+ scores each against the feature scope from Kickoff, and asks the user to confirm
218
+ the auto-selected subset before analysis.
219
+
220
+ #### Step a — Detect & unpack
221
+
222
+ For each zip path provided:
223
+
224
+ ```bash
225
+ file "<user-zip-path>"
226
+ ```
227
+
228
+ - If `file` does NOT report a Zip archive, treat the path as a regular file and
229
+ go back to step 1.6.4 point 2's "Otherwise" branch — no special handling.
230
+ - If it IS a zip, record in state:
231
+ - `mockups.archive.local_zip_path: <user-zip-path>` (absolute)
232
+ - `mockups.archive.kind: zip`
233
+ - Unpack into a scratch directory under the PRD's mockup folder:
234
+
235
+ ```bash
236
+ mkdir -p "$WORKTREE_PATH/${paths.prd_dir}/<slug>/mockups/_archive"
237
+ unzip -q "<user-zip-path>" \
238
+ -d "$WORKTREE_PATH/${paths.prd_dir}/<slug>/mockups/_archive/extracted"
239
+ ```
240
+
241
+ - Record `mockups.archive.extracted_dir`.
242
+ - If `unzip` fails (corrupted/encrypted): STOP, surface the exit code, ask the
243
+ user to verify the zip or provide an alternative.
244
+
245
+ #### Step b — Enumerate candidates
246
+
247
+ Scan the extracted tree for mockup-shaped files. The candidate filter is:
248
+
249
+ - Extensions: `.html`, `.htm`, `.png`, `.jpg`, `.jpeg`, `.svg`, `.webp`, `.gif`, `.pdf`.
250
+ - Exclude: `node_modules/`, `.git/`, anything under a directory named `assets/`
251
+ whose parent is itself excluded, `*.min.*`, `thumbs.db`, `.DS_Store`.
252
+ - Size sanity: skip files > 50 MB (likely video/binary blobs, never a mockup).
253
+
254
+ ```bash
255
+ find "$WORKTREE_PATH/${paths.prd_dir}/<slug>/mockups/_archive/extracted" \
256
+ -type f \
257
+ \( -iname '*.html' -o -iname '*.htm' -o -iname '*.png' -o -iname '*.jpg' \
258
+ -o -iname '*.jpeg' -o -iname '*.svg' -o -iname '*.webp' -o -iname '*.gif' \
259
+ -o -iname '*.pdf' \) \
260
+ -size -50M \
261
+ -not -path '*/node_modules/*' -not -path '*/.git/*' \
262
+ -not -name '*.min.*' -not -name 'thumbs.db' -not -name '.DS_Store'
263
+ ```
264
+
265
+ For each candidate, build a lightweight index entry:
266
+ - `path` (relative to `extracted/`)
267
+ - `filename`
268
+ - `ext`
269
+ - `size_kb`
270
+ - For HTML: `<title>` content + first `<h1>` (use `grep -oE` or a single Read of
271
+ the first ~200 lines; do NOT load the full file — they can be massive).
272
+ - For images: nothing extra at this stage (filename is the only cheap signal).
273
+
274
+ Cap the indexed list at 200 entries. If the archive contains more, sort by
275
+ `size_kb DESC` (larger files are typically the rendered screens) and keep the
276
+ top 200, recording `mockups.archive.truncated: true`.
277
+
278
+ Record the full index in state under `mockups.archive.candidates[]`.
279
+
280
+ #### Step c — Score against feature scope
281
+
282
+ Build the scope vector from the Kickoff state (Step 1):
283
+ - `feature_title` (from `## Feature Description`).
284
+ - `slug`.
285
+ - ISA touchpoints (if Discovery dimension 9 already ran).
286
+ - Verbatim screen names the user mentioned in the initial description.
287
+ - Keywords from `feature_objective_one_sentence` (strip stopwords).
288
+
289
+ For each candidate, compute a relevance score 0-100:
290
+ - `+40` if any scope keyword appears in the filename (case-insensitive,
291
+ whole-word; for kebab/snake/camelCase, split before matching).
292
+ - `+30` if any scope keyword appears in the HTML `<title>` or `<h1>`.
293
+ - `+15` if the file path contains a directory name matching a scope keyword.
294
+ - `+10` if the filename matches typical screen patterns (`screen`, `page`,
295
+ `view`, `flow`, the user's domain entity names).
296
+ - `-20` if the filename matches typical non-screen patterns (`icon`, `logo`,
297
+ `favicon`, `thumbnail`, `og-image`, `sitemap`, `manifest`).
298
+
299
+ Selection threshold: keep candidates with `score ≥ 30` as the auto-selected set.
300
+ If fewer than 3 candidates clear the threshold, lower to `≥ 20` and surface the
301
+ fact. If zero candidates clear `≥ 20`, surface "selezione non automatizzabile —
302
+ ti chiedo di indicarmi a mano quali sono rilevanti" and present the full
303
+ candidate list.
304
+
305
+ Record per-candidate: `score`, `matched_keywords[]`, `selected: bool`.
306
+
307
+ #### Step d — Confirmation gate (STOP)
308
+
309
+ Present a compact table to the user — selected candidates first, then up to 10
310
+ discarded with the highest scores, then a footer count for "altri N scartati":
311
+
312
+ ```
313
+ Bundle scaricato e analizzato: <N> file candidati, <K> selezionati come rilevanti.
314
+
315
+ **Selezionati** (score ≥ 30 vs. feature scope):
316
+ | # | File | Score | Match |
317
+ |---|-------------------------------|-------|------------------------|
318
+ | 1 | screens/lista-fornitori.html | 75 | "fornitori", "lista" |
319
+ | 2 | screens/dettaglio-ordine.html | 55 | "ordine" |
320
+
321
+
322
+ **Scartati ad alto score** (per trasparenza):
323
+ | # | File | Score | Motivo |
324
+ |---|-------------------------------|-------|------------------------|
325
+ | 1 | screens/landing-marketing.html| 22 | nessun keyword match |
326
+
327
+
328
+ Altri <M> file scartati (score < 20 o pattern non-schermata).
329
+
330
+ Procedo all'analisi visiva dei <K> selezionati? Oppure indicami modifiche
331
+ (es. "aggiungi il #3 degli scartati", "togli il #2 dei selezionati").
332
+ ```
333
+
334
+ **STOP.** Wait for explicit confirmation or an adjustment list. On adjustment,
335
+ recompute `mockups.archive.candidates[].selected`, then re-present and STOP again
336
+ until the user confirms.
337
+
338
+ #### Step e — Materialize the confirmed subset
339
+
340
+ Copy ONLY the confirmed selection into `${paths.prd_dir}/<slug>/mockups/`,
341
+ preserving relative directory structure under the extracted root so that
342
+ relative asset references (CSS, images) keep working. On filename collision,
343
+ use the `<name>-2.<ext>` rule from 1.6.4 point 2.
344
+
345
+ Record `mockups.original_paths[]` as `archive://<relative-path-in-zip>` and
346
+ `mockups.canonical_paths[]` as the new path under `mockups/`. The scratch
347
+ `_archive/extracted/` directory is kept for the duration of the PRD session
348
+ (may be needed to resolve `<link>` / `<img src>` references during analysis)
349
+ and cleaned up at Step 7 (Commit & Merge) — add a `.gitignore` entry for
350
+ `mockups/_archive/` if not already present.
351
+
352
+ Then continue to Step 1.6.5 with the selected subset.
353
+
200
354
  ### 1.6.5 — Mockup analysis (MANDATORY before Discovery)
201
355
 
202
356
  Analyze ALL provided mockups (visual analysis for chat images, Read for copied files
@@ -561,11 +715,26 @@ structure. Be specific — vague analysis defeats the purpose of skipping Step 3
561
715
  ```yaml
562
716
  mockups:
563
717
  status: provided | partial | none | requested
564
- format: chat-images | local-paths | mixed
718
+ format: chat-images | local-paths | local-archive | mixed
565
719
  original_paths:
566
- - <user-provided path or chat://image-N>
720
+ - <user-provided path, chat://image-N, or archive://<rel-path-in-zip>>
567
721
  canonical_paths:
568
- - mockups/<file>.png # only for local-paths
722
+ - mockups/<file>.png # only for local-paths and local-archive
723
+ archive: # only when format includes local-archive
724
+ local_zip_path: <abs path to the user-provided .zip>
725
+ kind: zip
726
+ extracted_dir: <abs path to _archive/extracted/>
727
+ truncated: false # true when candidate list capped at 200
728
+ candidates: # full enumerated list (post-filter)
729
+ - path: <rel path under extracted/>
730
+ filename: <basename>
731
+ ext: html | png | jpg | svg | …
732
+ size_kb: <int>
733
+ html_title: <optional, HTML only>
734
+ html_h1: <optional, HTML only>
735
+ score: <0-100>
736
+ matched_keywords: [<keyword>, …]
737
+ selected: <bool> # true = part of the confirmed subset
569
738
  mockup_analysis:
570
739
  screens:
571
740
  - name: <inferred name, e.g. "Lista ordini">
@@ -0,0 +1,119 @@
1
+ # MCP Integration — Guida BALDART per i consumer
2
+
3
+ Questo documento spiega **quando** un agent/skill BALDART deve appoggiarsi a un Model Context Protocol (MCP) server, **quali** MCP sono raccomandati per i casi d'uso più comuni, e **come** dichiarare la dipendenza MCP nel body dell'agent in modo che il consumer sappia subito cosa configurare.
4
+
5
+ > **Scope di questa release**: convenzione testuale, **zero nuove chiavi config** in `baldart.config.yml`. Le chiavi `mcp.*` (es. `mcp.required: []` / `mcp.optional: []`) entreranno solo se e quando una skill concreta dovrà gatearne il comportamento, in una release dedicata con propagazione end-to-end completa (regola di [schema-change propagation](../docs/PROJECT-CONFIGURATION.md)).
6
+
7
+ ---
8
+
9
+ ## 1. Quando usare un MCP
10
+
11
+ Tre opzioni per integrare un sistema esterno in un agent BALDART. Scegli il più semplice che risolve il problema:
12
+
13
+ | Opzione | Quando ha senso | Costi/limiti |
14
+ |---|---|---|
15
+ | **MCP server** | Il sistema è **bidirezionale**, ha molte operazioni discrete (search, get, mutate), serve a **molti agent diversi**, o richiede **stato di sessione** (browser, DB). | Setup nel consumer (configurazione MCP), dipendenza esplicita, esposizione dei dati al modello. |
16
+ | **Script CLI / Bash** | È un'azione **one-shot** o **idempotente** (build, test, git, lint, deploy), output testuale ben definito, niente stato di sessione. | Niente — è la baseline. Preferibile quando funziona. |
17
+ | **API call diretta (fetch/curl)** | Serve **un'unica chiamata** verso un endpoint REST/GraphQL pubblico o autenticato via env var, **non serve a più agent**. | Risposta opaca al framework (non recuperabile per altri agent), parsing manuale, niente cache strutturata. |
18
+
19
+ **Regola pratica**: se la stessa integrazione tornerà utile a **2+ agent o skill**, è un MCP. Se è un'esecuzione una-tantum da una singola skill, è uno script CLI o un fetch.
20
+
21
+ ---
22
+
23
+ ## 2. Catalogo MCP raccomandati per i casi d'uso comuni
24
+
25
+ Non è un'imposizione: BALDART non installa MCP, non li valida, non li richiede. È una lista curata di MCP che hanno senso nei deployment dove BALDART è già in uso.
26
+
27
+ ### Browser automation
28
+ - **Playwright MCP** (`@modelcontextprotocol/server-playwright`) — usato da [bug](../.claude/skills/bug/SKILL.md) e [webapp-testing](../.claude/skills/webapp-testing/SKILL.md) per cattura visiva, network, console.
29
+
30
+ ### Documentation retrieval (RAG)
31
+ - **doc-rag MCP** (interno o `@modelcontextprotocol/server-everything-search` come stand-in) — usato da [codebase-architect](../.claude/agents/codebase-architect.md) e [code-search-protocol.md](../agents/code-search-protocol.md) per ricerca semantica nei doc + knowledge graph.
32
+
33
+ ### Database
34
+ - **Firebase MCP** (`@modelcontextprotocol/server-firebase` — già integrato come plugin BALDART quando `stack.database.primary` è Firestore) — ispezione documenti, query collection, transazioni.
35
+ - **Postgres MCP** (`@modelcontextprotocol/server-postgres`) — per stack SQL.
36
+
37
+ ### Issue tracker / project management
38
+ - **GitHub MCP** (`@modelcontextprotocol/server-github`) o **`gh` CLI** — issue triage, PR review, gist creation. Per BALDART consigliamo `gh` (è una CLI già universale), MCP solo se servono molte mutazioni in pipeline.
39
+ - **Linear MCP**, **Jira MCP** — disponibili nella registry ufficiale Anthropic per chi usa quei ticketing system.
40
+
41
+ ### Design tool
42
+ - **Figma MCP** — usato da agent di design / UI per estrarre token, screenshot, asset.
43
+
44
+ ### Observability
45
+ - **Sentry MCP** — già disponibile in BALDART come [sentry plugin](../../CLAUDE.md). Per analisi error → root cause.
46
+
47
+ ### Communication
48
+ - **Slack MCP**, **Gmail MCP** — disponibili nel marketplace MCP. Usali solo se l'agent deve davvero comunicare verso umani (es. post-mortem auto-pubblicato).
49
+
50
+ **Anti-pattern**: NON installare MCP "perché esistono". Ogni MCP aggiunge tool al system prompt del modello, consuma context, e crea dipendenze infrastrutturali nel consumer. Il pattern BALDART è "tanti agent specializzati, pochi MCP universalmente utili".
51
+
52
+ ---
53
+
54
+ ## 3. La convenzione `## MCP dependencies` (per author di agent/skill BALDART)
55
+
56
+ Ogni agent o skill BALDART che usa MCP deve dichiararlo esplicitamente nel body, in una sezione dedicata. Questo permette:
57
+ - al **consumer** di sapere cosa configurare (e cosa succede se non lo configura);
58
+ - al `baldart doctor` futuro di leggere queste sezioni e verificare gli MCP `required`;
59
+ - ad altri agent di sapere se invocare questo agent è "free" o richiede setup.
60
+
61
+ ### Struttura
62
+
63
+ Subito dopo la sezione `## Project Context` (o, in mancanza, subito dopo il frontmatter e l'intro):
64
+
65
+ ```markdown
66
+ ## MCP dependencies
67
+
68
+ **Required** (skill/agent rifiuta o degrada visibilmente senza questi MCP):
69
+ - `mcp__<server>__<tool>` — cosa serve, perché.
70
+
71
+ **Optional** (l'agent ne approfitta se disponibile, ma ha un fallback):
72
+ - `mcp__<server>__<tool>` — cosa offre in più, qual è il fallback.
73
+
74
+ **None** (per skill senza MCP — utile dichiararlo esplicitamente):
75
+ - This skill uses no MCP servers. <breve nota se rilevante>
76
+ ```
77
+
78
+ ### Regole
79
+
80
+ 1. **Sii specifico**: cita il prefisso del tool (`mcp__playwright__browser_navigate`), non il "concetto" (`Playwright MCP`). Aiuta il consumer a fare grep.
81
+ 2. **Required vs Optional**: required = la skill non può completare il proprio task senza il MCP (o degrada gravemente). Optional = la skill ha un fallback funzionante.
82
+ 3. **Fallback espliciti**: per ogni `Optional`, descrivi il fallback in una frase ("se MCP unavailable, usa `rg` su `docs/` per trovare pattern noti").
83
+ 4. **Niente nuovo schema in `baldart.config.yml`**: non aggiungere `mcp.required` o `mcp.optional` nel config — è solo convenzione testuale finché non c'è una skill che ha bisogno di gatearne il comportamento a runtime.
84
+ 5. **Aggiorna la dichiarazione quando la dipendenza cambia**: se rimuovi un MCP dall'agent, rimuovi la riga; se aggiungi un fallback Grep e l'MCP diventa optional, sposta la riga.
85
+
86
+ ### Esempi nel framework corrente
87
+
88
+ Vedi le seguenti dichiarazioni per pattern di riferimento:
89
+ - [framework/.claude/agents/codebase-architect.md](../.claude/agents/codebase-architect.md) — `## MCP dependencies` con doc-rag required + LSP-related optional.
90
+ - [framework/.claude/skills/bug/SKILL.md](../.claude/skills/bug/SKILL.md) — Playwright required per UI bug, doc-rag + Firestore optional.
91
+ - [framework/.claude/skills/playwright-skill/SKILL.md](../.claude/skills/playwright-skill/SKILL.md) — esempio di sezione "None" (la skill usa Playwright Test CLI, non MCP).
92
+
93
+ ---
94
+
95
+ ## 4. FAQ per il consumer
96
+
97
+ **D: BALDART installa gli MCP per me?**
98
+ R: No. BALDART distribuisce agent e skill che eventualmente li **usano**. L'installazione e configurazione MCP è responsabilità del consumer (di solito via `.mcp.json` o `.claude/settings.json`). Vedi la [documentazione Claude Code](https://docs.claude.com) per il setup MCP.
99
+
100
+ **D: Cosa succede se invoco un agent che richiede un MCP non configurato?**
101
+ R: Dipende da come l'agent è stato scritto. Gli agent BALDART che seguono il pattern raccomandato fanno **graceful degrade** (riportano il missing MCP e provano un fallback documentato). Quelli che dichiarano un MCP come **Required** dovrebbero rifiutare visibilmente di proseguire — ma oggi BALDART non enforza questa policy in modo automatico. Il `baldart doctor` futuro potrà controllarla.
102
+
103
+ **D: Posso aggiungere un MCP custom non nella lista del § 2?**
104
+ R: Sì, e se diventa utile a più agent valuta una PR upstream a BALDART per aggiungerlo al catalogo. Vedi [MAINTAINING.md](../../MAINTAINING.md) per il workflow di contribuzione.
105
+
106
+ **D: La mia organizzazione ha un sistema interno (ticketing, docs, monitoring) — devo per forza esporlo via MCP?**
107
+ R: Non per forza. Se l'integrazione serve a **uno** script una tantum, una semplice fetch è meglio. Se serve a 2+ agent BALDART o se vuoi che gli agent possano "scoprire" dati senza che tu glieli passi manualmente, allora vale la pena un MCP custom.
108
+
109
+ ---
110
+
111
+ ## 5. Cosa cambia per BALDART nelle prossime release
112
+
113
+ Roadmap (vedi piano [gap-analysis vs. large codebases](../../.claude/plans/voglio-che-studi-questo-fluttering-nova.md)):
114
+
115
+ - **Adesso** (questa release): convenzione testuale `## MCP dependencies`, doc + 3 agent/skill aggiornati come reference.
116
+ - **Prossima release MINOR** (se serve): introduzione di una skill che richiede gating runtime su MCP → in quella release sarà propagata la chiave `mcp.required/optional` end-to-end (template + configure + doctor + CHANGELOG), seguendo la regola di schema-change propagation.
117
+ - **Routine `mcp-check`** (opzionale, T-level): controllo settimanale che ogni MCP `Required` dichiarato nel framework abbia un endpoint sano nel consumer.
118
+
119
+ Finché la chiave config non esiste, la convenzione testuale **è** il contratto.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "3.27.1",
3
+ "version": "3.28.1",
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"
@@ -7,6 +7,13 @@ const Hooks = require('../utils/hooks');
7
7
  async function add(repo, options) {
8
8
  const git = new GitUtils();
9
9
  const symlinks = new SymlinkUtils();
10
+ // Non-interactive flag honored on non-destructive prompts only. The
11
+ // "Remove and reinstall?" prompt (line 40) stays interactive even with
12
+ // --yes — that path requires explicit user intent, not flag inheritance.
13
+ // Callers that have already established intent (e.g. `update --reset`)
14
+ // rm -rf `.framework/` themselves, so `git.frameworkExists()` is false
15
+ // here and the destructive prompt is never reached.
16
+ const nonInteractive = options && options.yes === true;
10
17
 
11
18
  try {
12
19
  // Step 1: Verify environment
@@ -70,7 +77,9 @@ async function add(repo, options) {
70
77
  'Templates copied for customization'
71
78
  ]);
72
79
 
73
- const proceed = await UI.confirm('Install framework?', true);
80
+ const proceed = nonInteractive
81
+ ? true
82
+ : await UI.confirm('Install framework?', true);
74
83
  if (!proceed) {
75
84
  UI.info('Installation cancelled');
76
85
  process.exit(0);
@@ -157,13 +166,39 @@ async function add(repo, options) {
157
166
  // Configure Git aliases
158
167
  UI.section('Configuring Git Aliases');
159
168
 
160
- const configureAliases = await UI.confirm('Configure git aliases (fw-version, fw-update, fw-push)?', true);
169
+ const configureAliases = nonInteractive
170
+ ? true
171
+ : await UI.confirm('Configure git aliases (fw-version, fw-update, fw-push)?', true);
161
172
 
162
173
  if (configureAliases) {
163
- await git.git.addConfig('alias.fw-version', '!cat .framework/VERSION');
164
- await git.git.addConfig('alias.fw-update', '!npx github:antbald/BALDART update');
165
- await git.git.addConfig('alias.fw-push', '!npx github:antbald/BALDART push');
166
- UI.success('Git aliases configured');
174
+ // simple-git >=3.21 rejects shell-command aliases (prefix `!`) unless
175
+ // `allowUnsafeAlias` is set in its constructor — and even that is
176
+ // version-gated. Spawning `git config` directly bypasses the safety
177
+ // check (which is a simple-git policy, not a git policy: the user is
178
+ // explicitly opting in to these aliases here). Any failure here is
179
+ // cosmetic (the framework is fully installed without aliases), so we
180
+ // warn and continue instead of bubbling up to the global catch — that
181
+ // surfaced as "✗ Installation failed: Configuring alias is not
182
+ // permitted without enabling allowUnsafeAlias" while the install was
183
+ // actually fine.
184
+ const { spawnSync } = require('child_process');
185
+ const aliases = [
186
+ ['alias.fw-version', '!cat .framework/VERSION'],
187
+ ['alias.fw-update', '!npx baldart update'],
188
+ ['alias.fw-push', '!npx baldart push'],
189
+ ];
190
+ let aliasFailures = 0;
191
+ for (const [key, value] of aliases) {
192
+ const r = spawnSync('git', ['config', key, value], { stdio: 'pipe' });
193
+ if (r.status !== 0) {
194
+ aliasFailures += 1;
195
+ }
196
+ }
197
+ if (aliasFailures === 0) {
198
+ UI.success('Git aliases configured');
199
+ } else {
200
+ UI.warning(`${aliasFailures}/${aliases.length} git alias(es) could not be configured (non-blocking — install continues).`);
201
+ }
167
202
  }
168
203
 
169
204
  // BALDART hooks (multi-hook registry since v3.18.0)
@@ -201,10 +236,12 @@ async function add(repo, options) {
201
236
  // Skills now resolve project-specific facts from baldart.config.yml
202
237
  // instead of hard-coding paths. Configure prompts for these on install.
203
238
  UI.newline();
204
- const runConfigure = await UI.confirm(
205
- 'Configure project context now (paths, identity, stack, feature flags)?',
206
- true
207
- );
239
+ const runConfigure = nonInteractive
240
+ ? true
241
+ : await UI.confirm(
242
+ 'Configure project context now (paths, identity, stack, feature flags)?',
243
+ true
244
+ );
208
245
  if (runConfigure) {
209
246
  try {
210
247
  const configureCmd = require('./configure');
@@ -226,9 +263,13 @@ async function add(repo, options) {
226
263
  ' • Rename to lint-before-commit.sh',
227
264
  ' • Make executable: chmod +x .claude/hooks/lint-before-commit.sh',
228
265
  '',
229
- '2. Customize UI guidelines:',
230
- ' • Edit docs/references/ui-guidelines.template.md',
231
- ' Define colors, typography, spacing',
266
+ '2. Two editable templates landed at docs/references/ (untracked):',
267
+ ' • ui-guidelines.template.md — UI design language template.',
268
+ ' Edit and rename to ui-guidelines.md if you adopt it.',
269
+ ' • brand-guidelines.md — Brand voice & visual identity.',
270
+ ' Edit to taste, or delete if your project does not need one.',
271
+ ' These are starting points. Commit them to track your project\'s',
272
+ ' design language, or add them to .gitignore if you don\'t need them.',
232
273
  '',
233
274
  '3. Create backlog cards:',
234
275
  ' • Copy templates/feature-card.template.yml',
@@ -234,7 +234,12 @@ async function runReset(git, options, autoYes) {
234
234
  UI.newline();
235
235
  UI.info('Re-installing framework via `baldart add`…');
236
236
  const addCmd = require('./add');
237
- await addCmd({ yes: true });
237
+ // `add(repo, options)` first arg is the repo URL (undefined → use default
238
+ // from package.json). Pre-v3.28.1 we incorrectly passed `{ yes: true }` as
239
+ // the first arg, so `options` was undefined and every interactive prompt
240
+ // ("Install framework?", "Configure git aliases?", …) fired despite the
241
+ // parent `update --reset --yes --i-know` having already established intent.
242
+ await addCmd(undefined, { yes: true });
238
243
 
239
244
  // Post-restore sanity check — confirm nothing user-owned got clobbered.
240
245
  const stillPresent = {