baldart 3.25.0 → 3.27.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 +95 -0
- package/VERSION +1 -1
- package/bin/baldart.js +14 -0
- package/framework/.claude/hooks/agent-discovery-info.sh +30 -8
- package/framework/.claude/hooks/framework-edit-gate.js +13 -7
- package/framework/.claude/skills/baldart-update/SKILL.md +123 -73
- package/package.json +1 -1
- package/src/commands/doctor.js +67 -35
- package/src/commands/update.js +334 -13
- package/src/commands/version.js +60 -41
- package/src/utils/__tests__/classify-divergence.test.js +120 -0
- package/src/utils/git.js +199 -0
- package/src/utils/overlay-merger.js +36 -12
- package/src/utils/symlinks.js +58 -11
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,101 @@ 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.27.0] - 2026-05-28
|
|
9
|
+
|
|
10
|
+
Fix critico al meccanismo di overlay-merge degli agent. Sintomo riproducibile osservato in `mayo` durante `/new FEAT-0009 -full` (team mode, claude-opus-4-7): gli agent overlay-merged (`coder`, `ui-expert`, `code-reviewer`, `doc-reviewer`, `qa-sentinel`, `security-reviewer` quando hanno un overlay) **non comparivano nella lista "Available agent types"** del Claude Code session reminder. Sequenza concreta: `codebase-architect` (symlink) parte e completa; i 4 background agent (`coder×2` + `ui-expert×2`) lanciati subito dopo falliscono con `InputValidationError: subagent_type not recognized`; l'orchestratore halta con un AskUserQuestion fuori-protocollo. Repro: `ls -la .claude/agents/` mostra 21 symlink + 6 file regolari (i 6 overlay-merged); CC discoverizza i 21 symlink e omette i 6 file regolari. Confermato su sessioni indipendenti del 2026-05-27 e 2026-05-28 → bug strutturale, non transiente. Workflow `/new` in team mode, `/check`, `/qa`, `/codexreview` e skill `prd` erano **bloccati end-to-end** su qualsiasi consumer con overlay agent.
|
|
11
|
+
|
|
12
|
+
### Root cause — Claude Code upstream bug #20931
|
|
13
|
+
|
|
14
|
+
Il session-start discovery scanner di Claude Code che costruisce la registry di `subagent_type` validi **skippa silenziosamente i file regolari** in `.claude/agents/` (solo i symlink vengono caricati). Il bug è già documentato in `framework/.claude/hooks/agent-discovery-gate.js:10-15`:
|
|
15
|
+
|
|
16
|
+
> #20931 — file-based discovery of `.claude/agents/*.md` is documented as BROKEN in some scenarios (files ignored at session start)
|
|
17
|
+
|
|
18
|
+
Dalla v3.8.0 in poi BALDART ha generato i file overlay-merged come **file regolari** direttamente in `.claude/agents/<name>.md`, intersecando esattamente la zona di rottura di CC. Tutti gli overlay agent attivi nei consumer sono stati silenziosamente invisibili per ~3 mesi, e il sintomo emergeva solo quando una skill provava ad invocare lo `subagent_type` (es. team-mode `/new`).
|
|
19
|
+
|
|
20
|
+
Diagnosi precedente erroneamente attribuita a "HTML comment prima del frontmatter rompe il parser YAML" è stata rivista: il riordino del marker post-frontmatter resta una pulizia di formato corretta ma **non era la causa primaria** del sintomo.
|
|
21
|
+
|
|
22
|
+
### Fixed — Symlink indirection per agent/command overlay-merged (root cause fix)
|
|
23
|
+
|
|
24
|
+
- **[src/utils/symlinks.js](src/utils/symlinks.js)** `_generateOverlayedFile()`: il content merged ora vive in `.baldart/generated/<kind>s/<name>.md` (file regolare), e `.claude/agents/<name>.md` (o `.claude/commands/<name>.md`) viene creato come **symlink relativo** verso quel file. Claude Code vede il path consumer come un symlink come tutti gli altri e lo discoverizza correttamente. Stesso pattern per Codex (`.agents/skills/`) tramite il tool adapter.
|
|
25
|
+
- **[src/utils/symlinks.js](src/utils/symlinks.js)** `_installPerItemSymlink()`: quando `hasOverlay` viene rimosso e il path consumer è un symlink che punta in `.baldart/generated/`, il CLI relinka al framework base e cancella lo stale generated file. Coerenza forte tra "overlay esiste" e "esiste un generated file".
|
|
26
|
+
- **[src/utils/symlinks.js](src/utils/symlinks.js)**: migrazione automatica del legacy layout. Se il consumer ha un file regolare baldart-generated direttamente in `.claude/agents/<name>.md` (pre-v3.27.0), la prossima `npx baldart update` lo riconosce dal marker, sposta il content in `.baldart/generated/agents/<name>.md` e crea il symlink. Nessun intervento manuale richiesto. User-fork (file regolare senza marker baldart) restano protetti.
|
|
27
|
+
|
|
28
|
+
### Added — Safety net SessionStart hook
|
|
29
|
+
|
|
30
|
+
- **[framework/.claude/hooks/agent-discovery-info.sh](framework/.claude/hooks/agent-discovery-info.sh)**: oltre a rilevare gli agent **mancanti** (file assente), il hook ora rileva anche gli agent in **stato degradato** — ovvero file regolari con marker `<!-- baldart-generated: -->` presenti in `.claude/agents/` (pre-v3.27.0 layout). Quando rilevati, emette `additionalContext` esplicito al modello con il nome degli agent affected, la causa (upstream bug #20931) e l'azione richiesta (`npx baldart update`). Difesa-in-profondità: il `mergeAgents` migra automaticamente e questo hook copre l'edge case in cui un consumer non lanci `update` subito dopo l'upgrade.
|
|
31
|
+
|
|
32
|
+
### Fixed — Formato file generato (cleanup secondario, non root cause)
|
|
33
|
+
|
|
34
|
+
- **[src/utils/overlay-merger.js](src/utils/overlay-merger.js)**: i file generati hanno il frontmatter YAML su riga 1 e il marker `<!-- baldart-generated: -->` subito dopo il `---` di chiusura (era prima invertito). Allinea il formato alla convenzione standard CommonMark + YAML frontmatter, indipendentemente dal fatto che CC sia o meno strict sul parser.
|
|
35
|
+
- **[src/utils/overlay-merger.js](src/utils/overlay-merger.js)**: nuovo export `isGeneratedFile(content)` posizione-agnostico. `readMarker()` cerca il marker in tutto il file (cap 4KB) per leggere sia file v3.27.0+ sia legacy pre-v3.27.0 (retrocompat fondamentale per la migration).
|
|
36
|
+
- **[framework/.claude/hooks/framework-edit-gate.js](framework/.claude/hooks/framework-edit-gate.js)**: il PreToolUse hook controlla il marker via `head.includes` su slice 5KB, così intercetta edit ai file generati sia che il marker sia su riga 1 (legacy) sia dopo il frontmatter (v3.27.0+).
|
|
37
|
+
|
|
38
|
+
### Migration path per i consumer
|
|
39
|
+
|
|
40
|
+
Su un consumer con overlay agent in layout legacy (es. `mayo`):
|
|
41
|
+
|
|
42
|
+
1. `npx baldart update` rileva la nuova VERSION e lancia `mergeAgents`.
|
|
43
|
+
2. Per ogni file regolare baldart-generated in `.claude/agents/`: marker letto → content spostato in `.baldart/generated/agents/<name>.md` → simlink creato.
|
|
44
|
+
3. `git status` mostra: `.claude/agents/<name>.md` modificato (file → symlink), `.baldart/generated/agents/<name>.md` nuovo. La `_autoCommitFn` del CLI committa con `chore(baldart): post-update reconcile to v3.27.0`.
|
|
45
|
+
4. **Restart della Claude Code session** richiesto perché la registry di `subagent_type` viene letta al session-start.
|
|
46
|
+
5. Verifica: `Available agent types` ora include tutti i nomi (sia symlink che generated-symlink). `/new` in team mode funziona.
|
|
47
|
+
|
|
48
|
+
Nessuna perdita di overlay: i file in `.baldart/overlays/agents/*.md` sono consumer-owned e non vengono toccati. Lo skill `/baldart-update` cita esplicitamente nel report post-flight gli agent migrati e ricorda di restartare la sessione CC.
|
|
49
|
+
|
|
50
|
+
## [3.26.0] - 2026-05-27
|
|
51
|
+
|
|
52
|
+
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".
|
|
53
|
+
|
|
54
|
+
### Fixed — Bug "Already up to date" su consumer con update disponibili
|
|
55
|
+
|
|
56
|
+
- **[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`).
|
|
57
|
+
|
|
58
|
+
### Fixed — Falsi positivi "52 commit ahead / 20 unpushed" perenni
|
|
59
|
+
|
|
60
|
+
- **[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`).
|
|
61
|
+
|
|
62
|
+
### Added — Classifier divergenza subtree (Fix 2)
|
|
63
|
+
|
|
64
|
+
- **[src/utils/git.js](src/utils/git.js)**: nuova `classifyDivergence()` che ispeziona i commit consumer non in upstream e li categorizza branch-agnostic:
|
|
65
|
+
- `subtree-merge` (`Merge commit '*' into <any-branch>`) → auto-resolve silente.
|
|
66
|
+
- `subtree-squash` (`Squashed '.framework/' changes from *`) → auto-resolve silente.
|
|
67
|
+
- `chore-wrapper` (`[CHORE]` / `chore(baldart):` con `baldart` keyword nel subject o scope) → auto-resolve silente.
|
|
68
|
+
- `custom-overlay-able` (modifiche SOLO a file in `.framework/.claude/{agents,skills,commands}/`) → prompt: "Migra a overlay (raccomandato)".
|
|
69
|
+
- `custom-other` → prompt 3-way (push first / pull anyway / abort).
|
|
70
|
+
- Aggregate class `all-noise | overlay-able | real-custom | mixed | unknown`. Default conservativo `custom-other` per commit non riconosciuti — mai data loss silente.
|
|
71
|
+
- 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.).
|
|
72
|
+
|
|
73
|
+
### Added — CLI self-upgrade auto-relaunch (Fix 4)
|
|
74
|
+
|
|
75
|
+
- **[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.
|
|
76
|
+
|
|
77
|
+
### Added — `--reset` nuclear option (Fix 5)
|
|
78
|
+
|
|
79
|
+
- **[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>`.
|
|
80
|
+
|
|
81
|
+
### Added — Soppressione `ExperimentalWarning` (Fix 6)
|
|
82
|
+
|
|
83
|
+
- **[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`.
|
|
84
|
+
|
|
85
|
+
### Changed — Auto-backfill hook missing senza prompt (Fix 7)
|
|
86
|
+
|
|
87
|
+
- **[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.
|
|
88
|
+
|
|
89
|
+
### Changed — Skill `/baldart-update` parser tollerante + post-flight assert (Fix 9)
|
|
90
|
+
|
|
91
|
+
- **[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).
|
|
92
|
+
|
|
93
|
+
### Changed — Doctor planner usa version-compare authority
|
|
94
|
+
|
|
95
|
+
- **[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.
|
|
96
|
+
|
|
97
|
+
### Internal
|
|
98
|
+
|
|
99
|
+
- Nessuna nuova chiave in `baldart.config.yml`. Schema-change propagation rule non applicabile.
|
|
100
|
+
- `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).
|
|
101
|
+
- `hasChangesToPush()` resta in `git.js` per `push.js` che la usa correttamente (consumer's origin commits to push upstream).
|
|
102
|
+
|
|
8
103
|
## [3.25.0] - 2026-05-27
|
|
9
104
|
|
|
10
105
|
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`.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.27.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);
|
|
@@ -62,9 +62,19 @@ CONSUMER_AGENTS_DIR=".claude/agents"
|
|
|
62
62
|
|
|
63
63
|
[ -d "$FRAMEWORK_AGENTS_DIR" ] || exit 0 # consumer not installed — silent.
|
|
64
64
|
|
|
65
|
-
# --- compute missing
|
|
65
|
+
# --- compute missing + degraded sets --------------------------------------
|
|
66
|
+
#
|
|
67
|
+
# MISSING — file does not exist (or symlink is broken). agent-discovery-gate
|
|
68
|
+
# will hard-deny calls to these names.
|
|
69
|
+
# DEGRADED — file exists as a *regular file* with the baldart-generated marker.
|
|
70
|
+
# Pre-v3.27.0 layout produced these, but Claude Code upstream bug
|
|
71
|
+
# #20931 skips regular files at session-start discovery, so the
|
|
72
|
+
# `subagent_type` value is silently unavailable to the orchestrator.
|
|
73
|
+
# The fix is `npx baldart update` (migrates them to a symlink into
|
|
74
|
+
# .baldart/generated/<kind>s/).
|
|
66
75
|
|
|
67
76
|
MISSING=""
|
|
77
|
+
DEGRADED=""
|
|
68
78
|
while IFS= read -r f; do
|
|
69
79
|
[ -z "$f" ] && continue
|
|
70
80
|
name="$(basename "$f" .md)"
|
|
@@ -72,16 +82,21 @@ while IFS= read -r f; do
|
|
|
72
82
|
target="$CONSUMER_AGENTS_DIR/${name}.md"
|
|
73
83
|
# `test -e` returns false for broken symlinks too — exactly what we want.
|
|
74
84
|
if [ ! -e "$target" ]; then
|
|
75
|
-
if [ -z "$MISSING" ]; then
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
if [ -z "$MISSING" ]; then MISSING="$name"; else MISSING="$MISSING, $name"; fi
|
|
86
|
+
continue
|
|
87
|
+
fi
|
|
88
|
+
# File exists. If it's a symlink → CC discovery sees it, healthy.
|
|
89
|
+
# If it's a regular file with the baldart-generated marker → degraded
|
|
90
|
+
# state (legacy overlay layout before v3.27.0).
|
|
91
|
+
if [ ! -L "$target" ] && [ -f "$target" ]; then
|
|
92
|
+
if head -c 4096 "$target" 2>/dev/null | grep -q "<!-- baldart-generated:" ; then
|
|
93
|
+
if [ -z "$DEGRADED" ]; then DEGRADED="$name"; else DEGRADED="$DEGRADED, $name"; fi
|
|
79
94
|
fi
|
|
80
95
|
fi
|
|
81
96
|
done < <(find "$FRAMEWORK_AGENTS_DIR" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort)
|
|
82
97
|
|
|
83
|
-
# Nothing
|
|
84
|
-
[ -z "$MISSING" ] && exit 0
|
|
98
|
+
# Nothing to report — exit silently. No noise when everything is healthy.
|
|
99
|
+
[ -z "$MISSING" ] && [ -z "$DEGRADED" ] && exit 0
|
|
85
100
|
|
|
86
101
|
# --- emit additionalContext ----------------------------------------------
|
|
87
102
|
|
|
@@ -90,7 +105,14 @@ escape_json() {
|
|
|
90
105
|
printf '%s' "$1" | awk 'BEGIN{ORS=""} {gsub(/\\/,"\\\\"); gsub(/"/,"\\\""); gsub(/\r/,""); gsub(/\n/,"\\n"); print}'
|
|
91
106
|
}
|
|
92
107
|
|
|
93
|
-
MSG="
|
|
108
|
+
MSG=""
|
|
109
|
+
if [ -n "$MISSING" ]; then
|
|
110
|
+
MSG="BALDART expects the following sub-agents to be reachable via the Agent tool in this session, but their backing files are missing from .claude/agents/: ${MISSING}. Calling Agent with one of these subagent_type values will be denied by the agent-discovery-gate PreToolUse hook. Run \`npx baldart doctor\` to repair, then restart this session."
|
|
111
|
+
fi
|
|
112
|
+
if [ -n "$DEGRADED" ]; then
|
|
113
|
+
DEG_MSG="BALDART detected overlay-merged agents stored in the legacy pre-v3.27.0 layout (regular files in .claude/agents/ with the baldart-generated marker): ${DEGRADED}. Claude Code upstream bug #20931 silently skips regular files at session-start discovery, so calling Agent with one of these subagent_type values will fail with InputValidationError even though the file is on disk. Run \`npx baldart update\` to migrate to the v3.27.0+ symlink-indirection layout (the file is moved to .baldart/generated/<kind>s/<name>.md and .claude/agents/<name>.md becomes a symlink to it), then restart this session."
|
|
114
|
+
if [ -n "$MSG" ]; then MSG="${MSG} | ${DEG_MSG}"; else MSG="$DEG_MSG"; fi
|
|
115
|
+
fi
|
|
94
116
|
|
|
95
117
|
cat <<JSON
|
|
96
118
|
{
|
|
@@ -163,18 +163,24 @@ function main() {
|
|
|
163
163
|
|
|
164
164
|
// v3.8.0+: also block direct edits to BALDART-generated files (agents /
|
|
165
165
|
// commands generated from base + overlay). These live OUTSIDE .framework/
|
|
166
|
-
// but carry the baldart-generated marker comment
|
|
167
|
-
//
|
|
168
|
-
//
|
|
166
|
+
// but carry the baldart-generated marker comment in their head. Pre-v3.27.0
|
|
167
|
+
// the marker was on line 1; v3.27.0+ places it after the YAML frontmatter
|
|
168
|
+
// and the actual file lives in .baldart/generated/<kind>s/<name>.md with a
|
|
169
|
+
// symlink from .claude/agents/<name>.md. Match both layouts. The structural
|
|
170
|
+
// regex (requires kind=…name=…overlay_sha=…) avoids false-positives on
|
|
171
|
+
// framework source files that mention the marker as a string literal
|
|
172
|
+
// (e.g. this hook itself, agent-discovery-info.sh, overlay-merger.js).
|
|
173
|
+
const GENERATED_MARKER_RE =
|
|
174
|
+
/<!-- baldart-generated:[\s\S]{0,400}?kind=\S+[\s\S]{0,400}?name=\S+[\s\S]{0,400}?overlay_sha=\S+/;
|
|
169
175
|
try {
|
|
170
176
|
const fs = require('fs');
|
|
171
177
|
if (fs.existsSync(filePath)) {
|
|
172
|
-
const head = fs.readFileSync(filePath, 'utf8').slice(0,
|
|
173
|
-
if (
|
|
174
|
-
// Allow ONLY if the edit explicitly retains the marker
|
|
178
|
+
const head = fs.readFileSync(filePath, 'utf8').slice(0, 5000);
|
|
179
|
+
if (GENERATED_MARKER_RE.test(head)) {
|
|
180
|
+
// Allow ONLY if the edit explicitly retains the marker —
|
|
175
181
|
// catches accidental overwrites while letting BALDART itself regenerate.
|
|
176
182
|
const newContent = extractNewContent(toolName, input.tool_input) || '';
|
|
177
|
-
if (!
|
|
183
|
+
if (!GENERATED_MARKER_RE.test(newContent)) {
|
|
178
184
|
const reason =
|
|
179
185
|
`Cannot edit BALDART-generated file (${filePath}).\n` +
|
|
180
186
|
`This file is auto-generated by \`npx baldart update\` from a base ` +
|
|
@@ -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
|
|
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:
|
|
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.
|
|
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
|
-
##
|
|
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:
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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 —
|
|
233
|
+
### Step 3 — Run the CLI
|
|
199
234
|
|
|
200
235
|
```bash
|
|
201
|
-
|
|
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
|
-
|
|
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
|
-
|
|
242
|
+
Do NOT pass `--auto-stash` (redundant with `--yes`).
|
|
242
243
|
|
|
243
|
-
|
|
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
|
-
|
|
273
|
+
# Read the new installed version
|
|
274
|
+
cat .framework/VERSION
|
|
247
275
|
```
|
|
248
276
|
|
|
249
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,15 +304,31 @@ 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. **
|
|
277
|
-
|
|
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. **Agent layout migration (v3.27.0+)**: parse stdout for lines matching
|
|
316
|
+
`agent generated (overlay applied): .claude/agents/<name>.md → ../../.baldart/generated/agents/<name>.md`.
|
|
317
|
+
Pre-v3.27.0 overlay-merged agents (`coder`, `ui-expert`, `code-reviewer`,
|
|
318
|
+
`doc-reviewer`, `qa-sentinel`, `security-reviewer` when overlayed) lived
|
|
319
|
+
as regular files in `.claude/agents/` and were silently invisible to
|
|
320
|
+
Claude Code session-start discovery (upstream bug #20931). The CLI now
|
|
321
|
+
stores merged content in `.baldart/generated/<kind>s/<name>.md` and
|
|
322
|
+
places a symlink at `.claude/agents/<name>.md`. Report the migrated
|
|
323
|
+
names so the user knows they should restart their CC session for the
|
|
324
|
+
new layout to take effect on `subagent_type` resolution.
|
|
325
|
+
6. **Schema notes**: any missing key still flagged → suggest
|
|
278
326
|
`npx baldart configure`.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
doctor checks fired, suggest `npx baldart` (smart doctor).
|
|
327
|
+
7. **Stash-pop status**: clean / conflicts present (with file list).
|
|
328
|
+
8. **Suggested next step**: if schema drift residual or other non-update
|
|
329
|
+
doctor checks fired, suggest `npx baldart` (smart doctor). Also remind:
|
|
330
|
+
if any agent was migrated (step 5), **restart the Claude Code session**
|
|
331
|
+
so the discovery scanner sees the new symlinks.
|
|
282
332
|
|
|
283
333
|
## Failure modes
|
|
284
334
|
|