baldart 3.24.0 → 3.26.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,105 @@ 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.26.0] - 2026-05-27
9
+
10
+ Fix definitivo del processo `baldart update` dopo che un'esecuzione reale su un consumer (`mayo`) ha esposto un workflow strutturalmente rotto. Sintomi: `update --yes` stampava "Already up to date!" mentre `version`/`doctor` riportavano correttamente "Remote: 51 commit ahead"; CLI globale (v3.18.1) silenzioso vs npm latest (v3.24.0); divergenza subtree (19 commit locali + 51 upstream) mai menzionata; output sporcato da `ExperimentalWarning` di npm a ogni invocazione; skill `/baldart-update` che narrava il workflow rotto senza accorgersene. Root cause: tre superfici (`update`, `version`, `doctor`) implementavano TRE check diversi per la stessa domanda, e nessuna era giusta — `update.js:193` usava `hasChangesToPush()` (commit LOCALI non pushati al CONSUMER's origin, niente a che vedere con BALDART upstream); `version`/`doctor` usavano `HEAD...FETCH_HEAD` full-repo che include sempre subtree-merge noise → falso positivo perenne "52 commit ahead".
11
+
12
+ ### Fixed — Bug "Already up to date" su consumer con update disponibili
13
+
14
+ - **[src/utils/git.js](src/utils/git.js)** + **[src/commands/update.js](src/commands/update.js)**: nuova `getUpdateStatus(repo, branch)` SSOT basata su **VERSION compare** (`git show FETCH_HEAD:VERSION` vs `.framework/VERSION`), non sul commit count (che è strutturalmente rumoroso sul subtree). `update.js` Step 2 ora usa `status.isAligned` come segnale autoritativo. Eliminata la chiamata a `git.hasChangesToPush()` (rimane per compatibilità di `push.js`).
15
+
16
+ ### Fixed — Falsi positivi "52 commit ahead / 20 unpushed" perenni
17
+
18
+ - **[src/commands/version.js](src/commands/version.js)** + **[src/commands/doctor.js](src/commands/doctor.js)**: messaging riscritto su `isAligned`. `Remote: v3.26.0 (aligned)` quando OK, `Remote: v3.26.0 — update available (installed v3.22.1)` altrimenti. Il commit count migra dietro `version --verbose` (etichettato "subtree commit history — includes auto-generated merges"). Doctor `Local changes` mostra `unpushed commit(s)` SOLO se non-aligned (altrimenti tutto subtree-noise → riga `clean`).
19
+
20
+ ### Added — Classifier divergenza subtree (Fix 2)
21
+
22
+ - **[src/utils/git.js](src/utils/git.js)**: nuova `classifyDivergence()` che ispeziona i commit consumer non in upstream e li categorizza branch-agnostic:
23
+ - `subtree-merge` (`Merge commit '*' into <any-branch>`) → auto-resolve silente.
24
+ - `subtree-squash` (`Squashed '.framework/' changes from *`) → auto-resolve silente.
25
+ - `chore-wrapper` (`[CHORE]` / `chore(baldart):` con `baldart` keyword nel subject o scope) → auto-resolve silente.
26
+ - `custom-overlay-able` (modifiche SOLO a file in `.framework/.claude/{agents,skills,commands}/`) → prompt: "Migra a overlay (raccomandato)".
27
+ - `custom-other` → prompt 3-way (push first / pull anyway / abort).
28
+ - Aggregate class `all-noise | overlay-able | real-custom | mixed | unknown`. Default conservativo `custom-other` per commit non riconosciuti — mai data loss silente.
29
+ - Test fixture-driven: **[src/utils/__tests__/classify-divergence.test.js](src/utils/__tests__/classify-divergence.test.js)** con 24 fixture inclusi i pattern commit reali osservati nel debug di `mayo` (`[CHORE] reconcile baldart state ledger v3.22.1 -> v3.25.0`, `[CHORE] register baldart agent-discovery hooks`, ecc.).
30
+
31
+ ### Added — CLI self-upgrade auto-relaunch (Fix 4)
32
+
33
+ - **[src/commands/update.js](src/commands/update.js)** `maybeRelaunchUnderLatest()`: se il CLI globale è dietro npm latest, `update` rilancia trasparentemente `npx baldart@<latest> update <flags>` con `stdio: inherit` (preserva prompt). Loop guard via env `BALDART_RELAUNCHED=1` (impedisce ricorsione se npm cache serve ancora un vecchio). Fallback al CLI corrente se npx fallisce. Opt-out: `BALDART_NO_RELAUNCH=1`. Razionale rispetto a `update-notifier.js`: l'avvertenza "no auto-update globale" si riferisce a `npm i -g` silente; `npx@latest` è per-invocation, esplicito, opt-out → policy intatta.
34
+
35
+ ### Added — `--reset` nuclear option (Fix 5)
36
+
37
+ - **[bin/baldart.js](bin/baldart.js)** + **[src/commands/update.js](src/commands/update.js)** `runReset()`: `npx baldart update --reset` rimuove `.framework/` e reinstalla pulito, preservando `baldart.config.yml` + `.baldart/` (overlays, state.json) + `.claude/settings.json` + custom agents/skills/commands non-symlink. Safety gate obbligatorio: working tree clean (refusal se dirty), prompt esplicito per file untracked/ignored in `.framework/` (in `--yes` richiede ALSO `--i-know`), backup tag pre-rm. Post-restore sanity check: se un file user-owned è scomparso, refuse + suggest `git reset --hard <backup-tag>`.
38
+
39
+ ### Added — Soppressione `ExperimentalWarning` (Fix 6)
40
+
41
+ - **[bin/baldart.js](bin/baldart.js)**: `process.env.NODE_NO_WARNINGS = '1'` impostato ALL'INIZIO (prima di ogni `require`). Propagato a tutti i child process spawnati dal CLI (git, npx, ecc.). Verificato su Node 23.3.0: silenzia il warning. Escape hatch: `BALDART_VERBOSE_WARNINGS=1` lo riabilita. **Limite noto**: non silenzia il warning emesso da `npx` PRIMA che il nostro codice carichi — l'unico workaround è `npm i -g baldart` (modalità raccomandata) + invocazione diretta `baldart`.
42
+
43
+ ### Changed — Auto-backfill hook missing senza prompt (Fix 7)
44
+
45
+ - **[src/commands/update.js](src/commands/update.js)** logging: hook missing aggregati in una singola linea (`Auto-registered N missing hook(s): a, b, c`) invece di una per hook. La logica `Hooks.registerAll` era già corretta (auto-create silenzioso per missing, prompt solo per drift) — il cambio è cosmetico ma riduce noise post-update.
46
+
47
+ ### Changed — Skill `/baldart-update` parser tollerante + post-flight assert (Fix 9)
48
+
49
+ - **[framework/.claude/skills/baldart-update/SKILL.md](framework/.claude/skills/baldart-update/SKILL.md)**: Step 0 parser tollerante con 5 pattern in ordine (nuovo format `Remote: vX.Y.Z (aligned)`, format intermedio `update available`, legacy `N commit(s) ahead` / `up to date`, offline) — gestisce la finestra di transizione skill v3.26.0 + CLI globale v3.18.1. Se nessun pattern matcha → istruisce `npm i -g baldart@latest`. Eliminato Step 3 (hooks drift — ora auto-backfill in CLI) e Step 4 (auto-commit prompt — sempre yes in `--yes`). Step 6 ora include **post-flight assert obbligatorio**: confronta `.framework/VERSION` pre/post, FAIL LOUD se exit 0 ma VERSION invariata (safety net contro regression del Fix 1).
50
+
51
+ ### Changed — Doctor planner usa version-compare authority
52
+
53
+ - **[src/commands/doctor.js](src/commands/doctor.js)** `planActions()`: `remoteAhead = state.remote.fetched && state.remote.isAligned === false`. Label dell'action `update` ora `Update framework (vX.Y.Z → vA.B.C)` invece di `Pull N commit(s) from upstream`. Local-work detection sopprime commit count quando aligned.
54
+
55
+ ### Internal
56
+
57
+ - Nessuna nuova chiave in `baldart.config.yml`. Schema-change propagation rule non applicabile.
58
+ - `getRemoteVersion()` esistente non più consumato — VERSION compare ora dentro `getUpdateStatus()` via `git show FETCH_HEAD:VERSION`. La funzione resta per back-compat (status.js la chiama).
59
+ - `hasChangesToPush()` resta in `git.js` per `push.js` che la usa correttamente (consumer's origin commits to push upstream).
60
+
61
+ ## [3.25.0] - 2026-05-27
62
+
63
+ Strict-phase-gating + workspace-hygiene gates per `/new`. Risolve l'incident **FEAT-0006**: epic team-mode (4-layer L0→L1×5→L2×2→L3×2, 10 sub-card) che ha saltato per ogni card le fasi MANDATORY 2.5b (AC-Closure), 2.55 (Simplify), 2.6 (E2E-Review), 3 (Doc-Review), 3.5 (QA-Sentinel), 3.7 (Codexreview) — giustificazione documentata come "time budget", parola **inventata dal modello a runtime**, non esistente nella skill. In aggiunta, AC-IMG-3 "deferred dal coder 09" senza passare dal gate, e main repo lasciato con orphan commit non pushato + local `develop` diverged. Tre root cause radicate: (1) Phase 2.5b non era propagata in team-mode Step D, (2) coder `completion-report` accettava `status: partial`/`blocked` come terminale, (3) zero gate di workspace hygiene su `$MAIN`.
64
+
65
+ ### Added — Phase 0: Workspace Hygiene Pre-flight (BLOCKING)
66
+
67
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)**: nuova `## Phase 0` prima di `## Pre-flight (once)`. Su `$MAIN`: `fetch origin`, dirty-tree gate (`git status --porcelain` → `AskUserQuestion` con opzioni `[stash auto] / [commit ora] / [procedi senza stash] / [abort]`), divergence gate (`rev-list --left-right --count` → `AskUserQuestion` per ahead/behind/diverged). Stash ref salvato nel tracker sotto `## Workspace Snapshot` per il restore di Phase 6c. Anti-bypass guard finale che rifiuta di proseguire senza `## Phase 0: PASS` nel tracker. Auto Mode NON override.
68
+
69
+ ### Added — Phase 6c: Workspace Hygiene Post-merge (BLOCKING)
70
+
71
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)**: nuova `### Phase 6c` dopo Phase 6b. Parse del marker `[SYNC-DEFERRED]` emesso da `/mw`, clean-tree assertion, divergence assertion (cattura il pattern FEAT-0006 orphan commit con `AskUserQuestion` opzioni `[push adesso] / [cherry-pick] / [reset --hard con conferma esplicita] / [halt]`), restore dello stash di Phase 0 (con `AskUserQuestion` su conflict, mai silent drop). Anti-bypass guard come in Phase 0.
72
+
73
+ ### Added — Team-mode Step D rewrite (FEAT-0006 anti-regression)
74
+
75
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** righe ~1988: nuovo Step D con clausola di apertura esplicita ("La lean Step D è ora FORBIDDEN") + sub-step MANDATORY per-card propagati identici al sequential mode:
76
+ - **D.3a** — Phase 2.5b AC-Closure Gate per-card (sequenziale), bloccante.
77
+ - **D.3b** — Phase 2.55 Simplify per-card (diff per-card per attribuibilità).
78
+ - **D.3c** — Phase 2.6 E2E-Review per-card (honora il Gate table esistente — skip backend-only/docs/chore con motivazione documentata, mai con "time budget").
79
+ - **D.4a** — Phase 3 Doc Review per-card (oltre al D.2 combined).
80
+ - **Coverage assertion** end-of-group MANDATORY: prima di Step E, il tracker deve contenere per OGNI card le entry `AC Closure Ledger`, `simplify`, `e2e-review`, `doc-review`, `qa`, `codex-review`. Entry mancante → ritorno alla sub-step mancante. Documentare "skipped per time budget" è violazione esplicita.
81
+
82
+ ### Added — Top-of-file rigidity clause + tracker header
83
+
84
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)**: nuovo blockquote `> **NO PHASE SKIP FOR PERCEIVED TIME, EVER (BLOCKING)**` subito sotto SCOPE CLOSURE DISCIPLINE. Enumera esplicitamente le phrase forbidden (`time budget`, `context budget`, `context pressure as override`, `for time`, `to save tokens`, `to save iterations`). Self-correction trigger: se il modello produce una di queste phrase nel proprio output, deve fermarsi e routare via `AskUserQuestion`.
85
+ - **Tracker template** (~riga 50): HTML comment header che sopravvive alle compaction e ricorda la regola dopo ogni context recovery.
86
+
87
+ ### Changed — `coder` agent completion report (semantica binaria)
88
+
89
+ - **[framework/.claude/agents/coder.md](framework/.claude/agents/coder.md)**: card-level `status:` enum ridotto a `done | failed` (era `done | partial | failed`). Per-requirement e per-AC `status:` ridotto a `done | not_implemented` (era `done | partial | blocked`). Le legacy values `partial`/`blocked` erano usate come canali di silent deferral. Aggiunta a `Forbidden Actions`: "Don't defer acceptance criteria" + "Don't invent skip reasons". Retro-compatibile: coder che emettono ancora `partial` faranno triggerare il gate Phase 2.5b invece di passare in silenzio.
90
+
91
+ ### Changed — `framework/agents/workflows.md` Scope Closure Discipline
92
+
93
+ - Nuovo `### Coder authority (no defer)` in coda alla sezione: chiarisce che coder e orchestratori L0/L1 relay-ano i signal nel gate, non li aggregano/filtrano. Citable da skill e agent.
94
+
95
+ ### Changed — `/mw` `[SYNC-DEFERRED]` structured marker
96
+
97
+ - **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** righe ~835–855: quando `$MAIN` HEAD ≠ develop, oltre al `fetch` esistente emette ora `[SYNC-DEFERRED] main repo HEAD=<branch>, ...` su stdout. `/mw` standalone preserva l'isolamento terminale (no auto-checkout); orchestratori upstream (Phase 6c di `/new`) parsano il marker e routano la riconciliazione via user gate.
98
+
99
+ ### Why MINOR (not MAJOR)
100
+
101
+ Tutte le fasi MANDATORY esistevano già — vengono solo propagate (team-mode Step D) e rese non-bypassabili. Le nuove Phase 0/6c sono additive bloccanti, non rimuovono né rinominano capability. La semantica del `completion-report` cambia ma è retro-compatibile: coder pre-3.25 che emettono `partial`/`blocked` triggerano il gate invece di passare silently, e il gate ora esiste in team-mode. Per la decision tree in MAINTAINING.md "Tightened existing MANDATORY gates without removing capabilities → MINOR". L'incident FEAT-0006 era un fallimento di propagazione, non di design — la fix riallinea l'implementazione all'intent originale di v3.24.0.
102
+
103
+ ### Why no schema-change propagation
104
+
105
+ Modifiche testuali a 4 file framework. Zero chiavi nuove in `baldart.config.yml`, zero modifiche CLI (`src/commands/*`), zero hook nuovi, zero adapter, zero template. Considerato e scartato `policy.strict_phase_gating: true`: sarebbe 5 punti di propagazione (template + configure + update + skill + CHANGELOG) per zero beneficio tunable dall'utente — gli overlay `.baldart/overlays/new.md` restano la via per personalizzazioni progettuali. Verifica: `grep -r "policy.strict_phase_gating\|features.strict_phase_gating" framework/ src/` deve restituire vuoto.
106
+
8
107
  ## [3.24.0] - 2026-05-27
9
108
 
10
109
  Nuovo gate **AC-Closure** (Phase 2.5b) in `/new` + regola **Scope Closure Discipline** in `framework/agents/workflows.md`. Risolve il pattern ricorrente in cui l'orchestratore — sotto pressione di context-window o complessità inattesa — defer-iva unilateralmente acceptance criteria numerate marcandole `deferred` negli `implementation_notes` YAML con razionalizzazione post-hoc ("ApproveSheet già copre il confirm"). Caso reale che ha innescato la fix: sessione `/new` su FEAT-0005 (2026-05-27) dove 5 AC su 22 sono state silenziosamente deferite con razionalizzazione poi rivelata falsa alla verifica funzionale. Le decisioni di deferral sono ora **sempre routate all'utente via `AskUserQuestion`** una-per-AC.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.24.0
1
+ 3.26.0
package/bin/baldart.js CHANGED
@@ -1,5 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Suppress ExperimentalWarning noise from Node/npm internals (v3.25.0+).
4
+ // On Node 22+ npm emits a CommonJS/ESM ExperimentalWarning on every spawn —
5
+ // not actionable for our users, repeated on every invocation, illegible.
6
+ // Setting NODE_NO_WARNINGS in env BEFORE any spawn propagates to all
7
+ // child processes we launch (git, npx, etc). Cannot silence the warning
8
+ // emitted by `npx` itself BEFORE our code loads — for that, the
9
+ // recommended install is `npm i -g baldart` (then `baldart` direct).
10
+ // Escape hatch: BALDART_VERBOSE_WARNINGS=1 keeps them visible.
11
+ if (process.env.BALDART_VERBOSE_WARNINGS !== '1' && !process.env.NODE_NO_WARNINGS) {
12
+ process.env.NODE_NO_WARNINGS = '1';
13
+ }
14
+
3
15
  const { Command } = require('commander');
4
16
  const chalk = require('chalk');
5
17
  const fs = require('fs');
@@ -58,6 +70,8 @@ program
58
70
  .option('--no-commit', 'Skip the post-update auto-commit prompt')
59
71
  .option('-y, --yes', 'Auto-confirm all prompts (CI / scripting). Implies --auto-stash.')
60
72
  .option('--auto-stash', 'When the working tree is dirty, stash automatically instead of prompting.')
73
+ .option('--reset', 'Nuclear option: rm -rf .framework/ + fresh install, preserving baldart.config.yml + .baldart/ + custom .claude/{agents,skills,commands}/. Requires clean working tree.')
74
+ .option('--i-know', 'Acknowledges --reset will wipe untracked/ignored files inside .framework/ (required to use --reset --yes).')
61
75
  .action(async (options) => {
62
76
  const updateCommand = require('../src/commands/update');
63
77
  await updateCommand(options);
@@ -250,21 +250,22 @@ Do NOT wait until the end to verify your work. After each sub-task that changes
250
250
 
251
251
  ```completion-report
252
252
  card: <CARD-ID>
253
+ status: done | failed
253
254
  files_modified: [src/path/a.ts, src/path/b.ts]
254
255
  files_created: [src/path/new.ts]
255
256
  tsc_clean: true | false
256
257
  requirements:
257
258
  - id: 1
258
259
  text: "[verbatim requirement text from card]"
259
- status: done | partial | blocked
260
+ status: done | not_implemented
260
261
  evidence: "src/path/to/file.ts:LINE_NUMBER"
261
- notes: "[if partial or blocked: explain why; otherwise omit]"
262
+ notes: "[if not_implemented: state factually what is missing; do NOT propose deferral or rationalization]"
262
263
  - id: 2
263
264
  [repeat for each requirement]
264
265
  acceptance_criteria:
265
266
  - id: 1
266
267
  text: "[verbatim criterion text from card]"
267
- status: done | partial | blocked
268
+ status: done | not_implemented
268
269
  evidence: "src/path/to/file.ts:LINE_NUMBER"
269
270
  components_reused: [ComponentName from src/path]
270
271
  components_created: [NewComponent in src/path]
@@ -282,8 +283,10 @@ scope_boundaries_respected: true | false
282
283
  ```
283
284
 
284
285
  Rules for the report:
286
+ - `status` at card level is **binary**: `done` (all requirements and acceptance criteria are `done`) or `failed` (anything else, including a single `not_implemented` row). There is no `partial`. The orchestrator's AC-Closure Gate decides what happens with `failed` cards — your job is to report state truthfully.
287
+ - Per-requirement and per-AC `status` is **binary**: `done` or `not_implemented`. The legacy values `partial` and `blocked` are removed — they were used as silent deferral channels and the gate now intercepts them at the orchestrator. Report what is in the diff and what is not. Do not propose a verdict.
285
288
  - `evidence` MUST be a real file path and line number you actually wrote/modified — do NOT fabricate.
286
- - If a requirement is `partial` or `blocked`, the notes field is required.
289
+ - If a requirement or AC is `not_implemented`, the `notes` field is required and MUST describe factually what is missing (e.g. "no LCP measurement wired in `app/orders/page.tsx`"). It MUST NOT contain phrases like "deferred to follow-up", "covered by X", "out of scope", "redundant with Y", "time budget", "context pressure" — those are deferral verdicts and only the user issues verdicts via the gate.
287
290
  - List every requirement and acceptance criterion from the card — do not skip any.
288
291
  - `files_modified` and `files_created` MUST list every file you touched — downstream reviewers use this as their scope boundary.
289
292
  - `tsc_clean` MUST reflect the actual result of your last `npx tsc --noEmit` run.
@@ -312,6 +315,8 @@ Use judgment on review depth, but do not bypass repo-required QA gates.
312
315
  - Don't add dependencies without documenting them.
313
316
  - Don't force push without owner approval.
314
317
  - Don't invent alternative git workflows or testing gates.
318
+ - **Don't defer acceptance criteria.** Deferral is a user decision routed through the orchestrator's AC-Closure Gate (`AskUserQuestion`, one question per AC). You report `done` or `not_implemented`; the gate decides whether `not_implemented` becomes an approved deferral, a fix-loop, or a halt. Do NOT mark an AC as `partial`, `blocked`, `deferred`, `out of scope`, `redundant with X`, `covered by Y`, or any equivalent — those values do not exist for you.
319
+ - **Don't invent skip reasons.** Phrases like `time budget`, `context budget`, `context pressure as override`, `not in scope of this card`, `optional`, or any constraint not enumerated in the card YAML or in a phase's documented Gate table are forbidden. If you genuinely cannot make progress after 3 self-heal attempts, set the card-level `status: failed`, leave per-requirement statuses honest, and stop. The orchestrator handles the rest.
315
320
  - **NEVER create, checkout, or switch a git branch autonomously.** See the Hard Rule at the top of this file. No `git checkout -b`, no `git switch -c`, no `git branch`, no `git worktree add`. The `git_strategy` field is descriptive context, NOT authorization. Only an explicit literal instruction in the task prompt ("create branch X", "checkout Y") authorizes branch operations. When in doubt: stay on the current branch and report back in the completion report.
316
321
 
317
322
  Keep it simple. Write good code. Ask if unsure.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: baldart-update
3
- description: "Guidance for updating BALDART framework to the latest version in a consumer repo. Use when the user says /baldart-update, 'aggiorna baldart', 'aggiorna framework', 'update del framework', 'pull baldart latest', or wants to bring the framework up-to-date. Replicates all 5 native CLI decision points (preview diff, working tree stash, hooks drift, schema config drift, BALDART-managed auto-commit) as chat-side confirmations before launching `npx baldart update --yes` via Bash. For non-update drift, defers to `npx baldart` (smart doctor)."
3
+ description: "Guidance for updating BALDART framework to the latest version in a consumer repo. Use when the user says /baldart-update, 'aggiorna baldart', 'aggiorna framework', 'update del framework', 'pull baldart latest', or wants to bring the framework up-to-date. Replicates the native CLI's user-decision points (preview diff, working-tree stash) as chat-side confirmations, lets the CLI auto-resolve mechanical noise (hook backfill, subtree-merge commits, schema migration), and asserts post-flight that .framework/VERSION actually changed. For non-update drift, defers to `npx baldart` (smart doctor)."
4
4
  contamination_scan: skip
5
5
  ---
6
6
 
@@ -12,10 +12,10 @@ pull_request). When any of the numbers below changes against the actual
12
12
  sources, a warning is surfaced in the workflow run. The decision whether
13
13
  this skill needs an update is left to a human reviewer.
14
14
 
15
- update_js_prompts: 6
15
+ update_js_prompts: 7
16
16
  hook_registry_entries: 3
17
17
  config_template_top_level_keys: features,git,identity,lsp,paths,stack,tools,version
18
- last_verified: v3.21.2
18
+ last_verified: v3.26.0
19
19
  -->
20
20
 
21
21
 
@@ -122,15 +122,25 @@ for the protocol.
122
122
  how to proceed or aborts. Never silence a decision point because a
123
123
  probe failed.
124
124
 
125
- ## The 5 decision points the skill replicates
125
+ ## Decision points the skill still replicates (v3.26.0+)
126
+
127
+ Before v3.26.0 this skill chat-replicated five CLI decision points. As of
128
+ v3.26.0 the CLI itself silently auto-resolves three of them (hooks drift,
129
+ schema config drift, BALDART-managed auto-commit) when they don't involve
130
+ real user choices. The skill is now down to two prompts plus a mandatory
131
+ post-flight assert:
126
132
 
127
133
  | # | Native CLI prompt | Chat-side replication | Detect via |
128
134
  |---|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
129
- | 1 | "Proceed with update?" | Show "Remote: N commit(s) ahead" + last N commit messages, ask "Procedo?" | `npx baldart version` (parse "Remote: …" + "Repository: <url>") if N > 0, `git fetch <url> main && git log HEAD..FETCH_HEAD --oneline -- .framework/` |
135
+ | 1 | "Proceed with update?" | Show "Remote: vX.Y.Z" + (if known) last commit messages, ask "Procedo?" | `npx baldart version` (parse `Remote:` line with tolerant matcher see Step 0) |
130
136
  | 2 | "Stash dirty working tree?" | List modified files, explain they will go into `baldart-pre-update-<timestamp>`, ask explicit confirmation | `git status --porcelain` in consumer root |
131
- | 3 | Hooks drift prompt | Compare `.claude/settings.json` entries vs `HOOK_REGISTRY`; if drift, describe what backfill will change | `cat .claude/settings.json` + read `.framework/src/utils/hooks.js` for `HOOK_REGISTRY` |
132
- | 4 | Schema config migration | Compare `baldart.config.yml` keys vs `.framework/framework/templates/baldart.config.template.yml`; if missing keys, list which + consequence | semantic diff key-by-key (NOT textual diff) |
133
- | 5 | Auto-commit BALDART-managed | Classify `git status --porcelain` paths as BALDART-managed vs user-owned by path-prefix, show classification, confirm commit of the managed subset | path-prefix matching on `.framework/`, `.claude/agents/`, `.claude/skills/`, `.claude/commands/`, `AGENTS.md`, `agents/` |
137
+
138
+ **Auto-resolved by CLI in v3.26.0+** (no chat replication needed):
139
+ - **Hooks drift**: missing hooks auto-registered silently; only command-level drift prompts (and only if interactive).
140
+ - **Schema config drift**: surfaces as a warning post-update; never blocks.
141
+ - **BALDART-managed auto-commit**: `--yes` commits silently with `chore(baldart):` subject.
142
+ - **Subtree-merge / chore divergence commits**: classified by the CLI; auto-resolved silently when `all-noise`, prompts only for `overlay-able` / `real-custom` / `mixed`.
143
+ - **CLI self-upgrade**: transparent relaunch via `npx baldart@latest` when global CLI is stale.
134
144
 
135
145
  > **IMPORTANT — do NOT use `git -C .framework fetch`.** `.framework/` is a git
136
146
  > subtree, not a separate repo: git commands inside it fall back to the consumer's
@@ -145,19 +155,44 @@ for the protocol.
145
155
  ### Step 0 — Pre-flight (read-only)
146
156
 
147
157
  ```bash
148
- # One call gives both: installed version, behind count, and the
149
- # BALDART repo URL. NO git operation inside .framework/ — that
158
+ # One call gives installed version, remote version, alignment status, and
159
+ # the BALDART repo URL. NO git operation inside .framework/ — that
150
160
  # directory is a git subtree, not a separate repo.
151
161
  npx baldart version
152
162
  ```
153
163
 
154
- Parse the output for:
155
-
156
- - `Installed: vX.Y.Z` current framework version in the consumer.
157
- - `Remote: N commit(s) ahead pull with …` number of commits behind upstream. If this line is absent or shows 0, the consumer is up-to-date.
158
- - `Repository: <url>` — the BALDART git URL (needed in Step 1).
159
-
160
- If `Remote:` is absent / shows 0 → tell the user "Already up-to-date — version vX.Y.Z" and STOP. Do not launch the CLI.
164
+ **Parser tollerante** — the output format changed in v3.26.0 (version-compare
165
+ authority instead of subtree-merge commit count). The skill must accept BOTH
166
+ the new and legacy formats so it works during the transition window where
167
+ the consumer has the new skill but an older global CLI.
168
+
169
+ Match the `Remote:` line in this order (first match wins):
170
+
171
+ | # | Pattern (regex) | Meaning |
172
+ |---|--------------------------------------------------------------|--------------------------------------------------------------------|
173
+ | 1 | `Remote:\s+v(\S+)\s+\(aligned\)` | NEW — aligned, save `remoteVersion` for post-flight |
174
+ | 2 | `Remote:\s+v(\S+)\s+(?:—\|--)\s+update available` | NEW — NOT aligned, save `remoteVersion` |
175
+ | 3 | `Remote:\s+(\d+)\s+commit\(s\)\s+ahead` | LEGACY — count > 0 means NOT aligned (subtree-merge noise possible)|
176
+ | 4 | `Remote:\s+up to date` | LEGACY — aligned |
177
+ | 5 | `Remote:\s+\(offline.*\)` | unknown — ASK the user how to proceed |
178
+
179
+ Always also capture:
180
+ - `Installed:\s+v(\S+)` → `installedVersion` (saved for post-flight assert).
181
+ - `CLI:\s+v\S+\s+→\s+v(\S+)\s+available` → if present, tell the user once:
182
+ "Il CLI globale è vecchio (v<old> → v<new>). L'update lo gestirà
183
+ auto-relanciando via `npx baldart@latest` — niente da fare."
184
+
185
+ **Decision after parsing**:
186
+
187
+ - Patterns 1 or 4 → "Already up-to-date — version v<installedVersion>". STOP.
188
+ Do not launch the CLI.
189
+ - Patterns 2 or 3 → continue with Step 1 (preview + update).
190
+ - Pattern 5 → ask the user: "Vuoi forzare un fetch e ritentare, o procedere
191
+ in modalità offline (l'update fallirà nel CLI)?". STOP if unclear.
192
+ - **No pattern matches** → the CLI output format is unknown. Tell the user:
193
+ "Il CLI installato globalmente non emette un format riconosciuto.
194
+ Aggiorna il CLI con `npm i -g baldart@latest` e ri-invoca /baldart-update."
195
+ STOP.
161
196
 
162
197
  If `.framework/` does not exist, `npx baldart version` will say "framework not installed" — STOP and instruct `npx baldart add`. Do not attempt to recover.
163
198
 
@@ -195,73 +230,72 @@ chat, explain:
195
230
  If the user refuses → STOP, instruct them to commit or stash manually
196
231
  and re-run `/baldart-update`.
197
232
 
198
- ### Step 3 — Replicate decision points #3 + #4 (hooks/schema drift)
233
+ ### Step 3 — Run the CLI
199
234
 
200
235
  ```bash
201
- # Hooks drift detection
202
- cat .claude/settings.json
203
- # Compare entries against HOOK_REGISTRY in .framework/src/utils/hooks.js
204
- # (the skill reads both and reports any expected entry missing
205
- # or any installed entry with a stale config)
206
-
207
- # Schema drift detection
208
- # Compare top-level keys in baldart.config.yml against
209
- # .framework/framework/templates/baldart.config.template.yml
210
- ```
211
-
212
- For each drift detected, describe what `update.js` would do:
213
-
214
- - Hooks drift → "il CLI registrerà le hook mancanti in `settings.json`
215
- (entry: `baldart-<hook-name>`). Procedo?"
216
- - Schema drift → "il CLI segnalerà che mancano le chiavi `X.Y` da
217
- `baldart.config.yml` e suggerirà di rilanciare `npx baldart configure`
218
- dopo l'update. Procedo (l'update non bloccherà, ma è bene saperlo)?"
219
-
220
- If a probe fails (e.g. `settings.json` malformed), ask the user how to
221
- proceed — never silently assume "no drift".
222
-
223
- ### Step 4 — Replicate decision point #5 (auto-commit classification)
224
-
225
- ```bash
226
- git status --porcelain
236
+ npx baldart update --yes
227
237
  ```
228
238
 
229
- Classify each path:
230
-
231
- - **BALDART-managed**: starts with `.framework/`, `.claude/agents/`,
232
- `.claude/skills/`, `.claude/commands/`, `AGENTS.md`, `agents/`.
233
- - **User-owned**: everything else.
234
-
235
- Show the user the classification:
236
-
237
- > *"Dopo il pull, il CLI auto-committa SOLO i file BALDART-managed che
238
- > risultano modificati dal reconcile (es. symlink ricreati, agent/command
239
- > generati). I tuoi file user-owned non vengono toccati. Procedo?"*
239
+ **Use the Bash tool with `timeout: 600000`** (10 minutes). Capture stdout
240
+ and stderr — both are needed for Step 4.
240
241
 
241
- If no managed files would be modified, skip the prompt silently.
242
+ Do NOT pass `--auto-stash` (redundant with `--yes`).
242
243
 
243
- ### Step 5 Run the CLI
244
+ **What the CLI auto-resolves without prompting** (since v3.26.0):
245
+
246
+ - **Hooks drift**: missing hooks are auto-registered silently. Hooks with
247
+ modified commands stay user-customised (warning surfaced in `--yes` mode,
248
+ interactive prompt otherwise).
249
+ - **Schema config drift**: new config keys are reported as a warning; the
250
+ user is told to run `npx baldart configure` later. The update never
251
+ blocks on schema drift.
252
+ - **BALDART-managed auto-commit**: in `--yes` mode the CLI commits any
253
+ files it touched during the reconcile with `chore(baldart): post-update
254
+ reconcile to vX.Y.Z`. User-owned files are never staged.
255
+ - **Subtree-merge / chore divergence commits**: when the consumer has
256
+ local commits that are just `git subtree pull` plumbing or CLI-generated
257
+ `[CHORE]` commits, the CLI auto-resolves silently. Real user-custom
258
+ commits ABORT in `--yes` mode (the user must re-run without `--yes` to
259
+ choose).
260
+ - **CLI self-upgrade**: if the global CLI is older than npm latest, the
261
+ update transparently relaunches itself via `npx baldart@latest update
262
+ --yes`. Loop-guarded by `BALDART_RELAUNCHED=1`.
263
+
264
+ The skill no longer chat-replicates these decision points — they are
265
+ either silent (no user choice involved) or only triggered by genuine
266
+ user content, in which case the CLI surfaces the prompt directly.
267
+
268
+ ### Step 4 — Post-flight assert + Report
269
+
270
+ **Post-flight assert (MANDATORY — safety net against silent CLI bugs)**:
244
271
 
245
272
  ```bash
246
- npx baldart update --yes
273
+ # Read the new installed version
274
+ cat .framework/VERSION
247
275
  ```
248
276
 
249
- **Use the Bash tool with `timeout: 600000`** (10 minutes). Capture stdout
250
- and stderr — both are needed for Step 6.
251
-
252
- Do NOT pass `--auto-stash` (redundant with `--yes`).
277
+ Compare against `installedVersion_before` saved in Step 0:
253
278
 
254
- ### Step 6 Report
279
+ - **If `before === after` AND stdout DOES NOT contain "Already up to date"** →
280
+ the CLI exited 0 but the framework didn't actually update. **FAIL LOUD**:
281
+ ```
282
+ ✗ Update CLI exited 0 but .framework/VERSION did not change.
283
+ Before: v<before> | After: v<after>
284
+ This is a CLI bug — please report the full stdout/stderr above.
285
+ The repo is in an inconsistent state; do NOT continue assuming success.
286
+ ```
287
+ Do NOT report success. Do NOT mark the task complete.
288
+ - **If stdout contains "Already up to date" but Step 0 had a `remoteVersion`
289
+ different from `installedVersion`** → same FAIL LOUD (this is the v3.24.x
290
+ bug regression check — Fix 1 of v3.26.0 must not regress).
291
+ - Otherwise → success path.
255
292
 
256
- Extract the post-update facts and surface them:
293
+ Then extract the post-update facts and surface them:
257
294
 
258
295
  ```bash
259
296
  # Backup tag (most recent baldart-pre-update-* tag)
260
297
  git tag -l 'baldart-pre-update-*' --sort=-creatordate | head -1
261
298
 
262
- # New installed version
263
- cat .framework/VERSION
264
-
265
299
  # Stash-pop conflicts (if any)
266
300
  # Grep stdout/stderr for: CONFLICT, "stash pop failed", "unmerged paths"
267
301
  # If matches found, list the conflicted paths:
@@ -270,14 +304,18 @@ git status --porcelain | grep '^UU'
270
304
 
271
305
  Report to the user, in order:
272
306
 
273
- 1. **Version**: `vX.Y.Z → vA.B.C` (delta).
307
+ 1. **Version**: `vX.Y.Z → vA.B.C` (delta — both from `cat .framework/VERSION`
308
+ pre and post).
274
309
  2. **Backup tag**: the `baldart-pre-update-<timestamp>` ref, with the
275
310
  rollback command: `git reset --hard <tag>` (only if needed).
276
- 3. **Hooks reconciled**: any hook backfilled.
277
- 4. **Schema notes**: any missing key still flagged suggest
311
+ 3. **CLI self-upgrade**: if stdout mentions "Auto-relaunching via npx
312
+ baldart@…", surface it once so the user knows the CLI bumped too.
313
+ 4. **Hooks reconciled**: any hook backfilled (parse "Auto-registered N
314
+ missing hook(s)" or per-line "Registered hook" from stdout).
315
+ 5. **Schema notes**: any missing key still flagged → suggest
278
316
  `npx baldart configure`.
279
- 5. **Stash-pop status**: clean / conflicts present (with file list).
280
- 6. **Suggested next step**: if schema drift residual or other non-update
317
+ 6. **Stash-pop status**: clean / conflicts present (with file list).
318
+ 7. **Suggested next step**: if schema drift residual or other non-update
281
319
  doctor checks fired, suggest `npx baldart` (smart doctor).
282
320
 
283
321
  ## Failure modes