baldart 4.55.0 → 4.55.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,16 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.55.1] - 2026-06-19
9
+
10
+ **`baldart doctor`'s toolchain fresh-write paths now also wire the i18n pre-commit command (v4.55.0 follow-up).** v4.55.0 wired the guarded `i18n` lefthook command only through `configure`. The doctor backfill actions that write a FRESH `lefthook.yml` — `toolchain-install` (when lefthook resolves after a devDep install) and `toolchain-init-config` (restore a missing default config) — did not pass `i18nCommand`, so a `lefthook.yml` born from a doctor backfill on a `has_toolchain` + `has_i18n` project would be Biome-only. Both now compute the resolved (trailing-` .`-stripped) i18n command from `state.i18nEnabled` and pass it through, exactly like `configure`. Fresh-write only (`initConfig` still skips an existing file); the `i18n-precommit-snippet` WARN still covers an already-present Biome-only `lefthook.yml` (no duplication — the snippet check requires the file to exist).
11
+
12
+ **PATCH** (closes a fresh-write gap in doctor; no behaviour change for projects without `has_i18n`; no new agent/skill/command/key, no install/layout change).
13
+
14
+ ### Fixed
15
+
16
+ - **`src/commands/doctor.js`** — `toolchain-install` + `toolchain-init-config` actions pass `i18nCommand` to `ToolchainInstaller.install` / `initConfigs` when `has_i18n`.
17
+
8
18
  ## [4.55.0] - 2026-06-19
9
19
 
10
20
  **The i18n anti-hardcoded gate now also runs as a guarded lefthook pre-commit command — closing the direct-commit hole for projects that have BOTH the toolchain and i18n enabled.** Until now the gate ran only inside the BALDART workflows (`/new`, `/new2`, `/qa`, qa-sentinel, routine), so a *direct* `git commit` (a human, or an agent editing outside `/new`) bypassed it. When `features.has_toolchain` AND `features.has_i18n` are both true, a fresh `lefthook.yml` now gains an `i18n` pre-commit command that runs the standalone anti-hardcoded gate over `{staged_files}`. It is **guarded** (`sh -c 'if [ -f eslint.i18n.config.mjs ] || …; then exec <cmd> "$@"; fi'`): the gate's non-zero exit propagates (a hardcoded JSX string fails the commit), but when the gate config is absent it is a clean no-op (exit 0) — never a spurious block. Bypassable with `git commit --no-verify` (a strong default, not a wall); covers JSX text + allowlisted attributes (`jsx-only`); the non-JSX backstop stays with `code-reviewer`; consumers without the toolchain keep the `/new`/qa-sentinel gates as enforcement.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.55.0
1
+ 4.55.1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.55.0",
3
+ "version": "4.55.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"
@@ -900,7 +900,10 @@ function planActions(state) {
900
900
  autoOk: false, // installs devDependencies; let the user confirm
901
901
  run: async () => {
902
902
  const ti = new ToolchainInstaller(state.cwd);
903
- const res = ti.install({ tools: state.toolchainMissingTools });
903
+ // When has_i18n, a fresh lefthook.yml written here also gets the guarded
904
+ // i18n pre-commit command (v4.55.1) — same as configure. Fresh-write only.
905
+ const i18nCmd = state.i18nEnabled ? I18nGate.commandForCwd(state.cwd).replace(/\s+\.$/, '') : null;
906
+ const res = ti.install({ tools: state.toolchainMissingTools, i18nCommand: i18nCmd });
904
907
  for (const t of res.installed) UI.success(`Installed ${t}.`);
905
908
  for (const f of res.failed) UI.warning(`Install failed for ${f.tool}: ${f.error}`);
906
909
  for (const s of res.skipped) UI.info(`Skipped ${s.tool}: ${s.reason}`);
@@ -915,7 +918,9 @@ function planActions(state) {
915
918
  autoOk: true, // only writes an absent default config
916
919
  run: async () => {
917
920
  const ti = new ToolchainInstaller(state.cwd);
918
- const cfgRes = ti.initConfigs({ tools: state.toolchainMissingConfigs });
921
+ // Fresh-write path: include the guarded i18n command when has_i18n (v4.55.1).
922
+ const i18nCmd = state.i18nEnabled ? I18nGate.commandForCwd(state.cwd).replace(/\s+\.$/, '') : null;
923
+ const cfgRes = ti.initConfigs({ tools: state.toolchainMissingConfigs, i18nCommand: i18nCmd });
919
924
  for (const c of cfgRes) {
920
925
  if (c.status === 'written') UI.success(`Wrote default ${c.tool} config.`);
921
926
  else UI.info(`${c.tool}: ${c.reason || c.status}`);