baldart 4.52.1 → 4.52.2

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,14 @@ 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.52.2] - 2026-06-18
9
+
10
+ **Anti-hardcoded gate: kill the false positives — the generated ESLint config now allowlists only user-facing JSX attributes.** v4.52.0's `mode: 'jsx-only'` flagged *every* JSX attribute string, so on a real component-heavy codebase it drowned the signal in technical props — `variant="inset"`, `size="lg"`, `href="/login"`, `padding="md"` were all reported as "hardcoded user-facing strings". Measured on a production app: **3260 raw findings, mostly false positives.** Fixed by adding `'jsx-attributes': { include: ['placeholder','title','alt','label','aria-label'] }` to the generated `eslint.i18n.config.mjs` / `.eslintrc.i18n.json`, so attribute checks are restricted to the genuinely user-facing ones while JSX text nodes are still fully checked. Same codebase after the fix: **~1500 findings, 0 technical-attribute false positives** — every remaining finding is a real hardcoded label. Verified against `eslint-plugin-i18next`'s `shouldSkip` include-allowlist semantics. **PATCH** (tightens the generated gate config to be usable on real codebases; no new key, no behaviour change beyond fewer false positives).
11
+
12
+ ### Fixed
13
+
14
+ - **`src/utils/i18n-gate.js`** — both the flat (ESLint 9) and legacy (ESLint 8) generated configs now carry the `jsx-attributes.include` user-facing allowlist; `framework/agents/i18n-protocol.md` cascade updated to describe the precise coverage (JSX text + 5 user-facing attributes; technical props excluded).
15
+
8
16
  ## [4.52.1] - 2026-06-18
9
17
 
10
18
  **Hotfix: `baldart configure` (and the `configure-drift` doctor action) crashed with `detectedI18nFramework is not defined` whenever the i18n block ran.** The v4.52.0 i18n config block lives in `interactivePrompts()`, but referenced two helpers (`detectedI18nFramework`, `detectLocalesRoot`) that are scoped to the separate `detect()` function — a `ReferenceError` the moment `features.has_i18n` was true (so the framework / locales-root prompt defaults threw, taking down configure and the doctor drift action). Fixed by passing the detected values through the `detected` object (`detected.i18n.{framework,locales_root}` — real snake_case keys that also seed `merged.i18n.*` via the existing merge, no junk serialized). Also **broadened i18n framework autodetection** to `next-i18next` / `react-i18next` (→ i18next) and `@nuxtjs/i18n` / `@nuxt/i18n` (→ vue-i18n), so the `has_i18n` flag defaults to Yes on those stacks instead of being silently skipped. **PATCH** (bugfix to a v4.52.0 CLI path; no behaviour change beyond fixing the crash + wider detection; no new `baldart.config.yml` key).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.52.1
1
+ 4.52.2
@@ -74,9 +74,11 @@ Translations are NOT stored here — they live in the native locale files.
74
74
  convention when the file exists → SKIP (never a silent pass). It is a dedicated
75
75
  ESLint run **independent of the project's main lint** (so it works even on a
76
76
  Biome-only toolchain) and **never touches the user's config**. The default rule
77
- mode is `jsx-only`: it deterministically blocks **JSX text nodes AND user-facing
78
- JSX attributes** (`title`/`placeholder`/`alt`/`aria-label`) — verified to FAIL on
79
- a hardcoded label and PASS on `t()`. Runners: `qa-sentinel` (for `/new`, `/qa`),
77
+ mode is `jsx-only` with a `jsx-attributes.include` allowlist: it deterministically
78
+ blocks **JSX text nodes AND the user-facing attributes** `placeholder`/`title`/`alt`/
79
+ `label`/`aria-label`, while **technical props** (`variant`/`size`/`href`/`className`/
80
+ `type`/…) are NOT flagged — verified on a real codebase (3260 raw findings → ~1500
81
+ genuine, 0 technical-attribute false positives). Runners: `qa-sentinel` (for `/new`, `/qa`),
80
82
  the classic `/new` Phase-2 gate, the `new2` Phase-2 gate, and the `i18n-align`
81
83
  routine (pre-commit). This is the HARD enforcement for JSX-rendered strings.
82
84
  2. **Semantic backstop (review)** — non-JSX imperative strings are OUTSIDE the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.52.1",
3
+ "version": "4.52.2",
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"
@@ -47,10 +47,11 @@ const FLAT_BODY = `// BALDART-owned i18n anti-hardcoded gate (generated by \`bal
47
47
  // main ESLint setup. ESLint 9 flat config. Run via: ${FLAT_COMMAND}
48
48
  //
49
49
  // Fails when a user-facing string is hardcoded instead of routed through your i18n
50
- // translation function. \`mode: '${MODE}'\` flags JSX text AND user-facing
51
- // attributes (title/placeholder/alt/aria-label). Broaden to 'all' for non-JSX
52
- // strings too, or add to \`ignores\` / the rule allowlist — BALDART writes this file
53
- // only when absent and never overwrites your edits.
50
+ // translation function. \`mode: '${MODE}'\` checks JSX text; \`jsx-attributes.include\`
51
+ // restricts ATTRIBUTE checks to the user-facing ones only (placeholder/title/alt/
52
+ // label/aria-label) so technical props (variant/size/href/className/type/…) are NOT
53
+ // flagged as false positives. Broaden the include list (or \`mode: 'all'\`) for stricter
54
+ // coverage — BALDART writes this file only when absent and never overwrites your edits.
54
55
  import i18next from 'eslint-plugin-i18next';
55
56
  import tseslint from 'typescript-eslint';
56
57
 
@@ -67,7 +68,10 @@ export default [
67
68
  },
68
69
  plugins: { i18next },
69
70
  rules: {
70
- 'i18next/no-literal-string': ['error', { mode: '${MODE}' }],
71
+ 'i18next/no-literal-string': ['error', {
72
+ mode: '${MODE}',
73
+ 'jsx-attributes': { include: ['placeholder', 'title', 'alt', 'label', 'aria-label'] },
74
+ }],
71
75
  },
72
76
  },
73
77
  ];
@@ -78,7 +82,12 @@ const LEGACY_BODY = JSON.stringify({
78
82
  parser: '@typescript-eslint/parser',
79
83
  parserOptions: { ecmaFeatures: { jsx: true }, sourceType: 'module' },
80
84
  plugins: ['i18next'],
81
- rules: { 'i18next/no-literal-string': ['error', { mode: MODE }] },
85
+ rules: {
86
+ 'i18next/no-literal-string': ['error', {
87
+ mode: MODE,
88
+ 'jsx-attributes': { include: ['placeholder', 'title', 'alt', 'label', 'aria-label'] },
89
+ }],
90
+ },
82
91
  ignorePatterns: ['node_modules/', 'dist/', 'build/', '.next/', 'out/', 'coverage/', '*.test.*', '*.spec.*'],
83
92
  }, null, 2) + '\n';
84
93