baldart 3.14.0 → 3.14.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 +24 -15
- package/VERSION +1 -1
- package/package.json +1 -1
- package/src/utils/git.js +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.14.1] - 2026-05-23
|
|
9
|
+
|
|
10
|
+
Hotfix for the `.framework/` gitignore self-heal shipped in v3.14.0. The detector misread `git check-ignore -v` output: when `check-ignore` matched a negation pattern (`!.framework`), it still reported the match, and `checkFrameworkIgnored` flagged the path as ignored. The result: every consumer who hit the self-heal on first run got `.framework/ is STILL ignored after auto-heal` and `process.exit(1)` — the heal *had* actually worked (the negation was in place), but the verifier didn't recognize its own fix. Reported during the v3.13.0 → v3.14.0 update in a downstream consumer.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`GitUtils.checkFrameworkIgnored()` recognizes negation patterns** in `src/utils/git.js`. Per `gitignore(5)`, a leading `!` flips the match semantics: `check-ignore` still prints the pattern (matching ≠ ignored), but the path is RE-INCLUDED, not ignored. The detector now inspects the pattern, returns `{ ignored: false, negatedBy }` on a negation match, and `ensureFrameworkNotIgnored`'s post-heal recheck reports `stillIgnored: false` as expected. Smoke-tested end-to-end: `.gitignore` with `.framework` → heal → recheck reports not-ignored → idempotent second call is a no-op → `git add .framework/foo` succeeds.
|
|
15
|
+
- **CHANGELOG consolidation for v3.14.0.** The original 3.14.0 entry had a duplicate `### Added` / `### Notes` block (LSP-only Notes + gitignore-only Notes side by side). Merged into a single Notes section so the release reads as one feature shipped, not two.
|
|
16
|
+
|
|
17
|
+
### Notes
|
|
18
|
+
|
|
19
|
+
- **v3.14.0 is functionally broken on first install of the heal.** Consumers who upgrade `npm i -g baldart@latest` get 3.14.1 directly and never observe the regression. Consumers who already updated to 3.14.0 (CLI binary or `npx baldart`) should reinstall: `npm i -g baldart@latest`, then re-run `baldart` — the heal converges on the second pass because the negation block already in `.gitignore` short-circuits the detector cleanly.
|
|
20
|
+
- **No framework payload changes.** Single-file fix in `src/utils/git.js` plus CHANGELOG.
|
|
21
|
+
|
|
8
22
|
## [3.14.0] - 2026-05-23
|
|
9
23
|
|
|
10
24
|
BALDART closes the **LSP install completeness gap** AND adds a long-overdue **`.framework/` gitignore self-heal** so install / update / push never trip over a stale or pre-existing ignore rule.
|
|
@@ -13,8 +27,15 @@ BALDART closes the **LSP install completeness gap** AND adds a long-overdue **`.
|
|
|
13
27
|
|
|
14
28
|
Since v3.10.0, opting into `features.has_lsp_layer: true` installed the language-server binary (typescript-language-server, pyright, gopls, rust-analyzer, ruby-lsp) into the consumer repo — but the matching native Claude Code plugin (`<lang>-lsp@claude-plugins-official`) was left for the user to install manually via `/plugin install`. Almost nobody did, so Claude itself never invoked the LSP and code-exploration silently fell back to Grep. The "opt-in to LSP" UX was effectively broken: users thought they had it, agents behaved as if they didn't. v3.14.0 wires the two layers together — when the user opts into LSP, BALDART now installs the binary AND enables the native plugin in the same `configure` step, idempotently and gated on `claude` being in `tools.enabled`.
|
|
15
29
|
|
|
30
|
+
### `.framework/` `.gitignore` self-heal
|
|
31
|
+
|
|
32
|
+
The other historical sharp edge in BALDART: consumers who had `.framework` (or a parent pattern like `framework/` or `*framework*`) in `.gitignore` saw every `baldart push` and most `baldart update` autofix flows blow up with `paths are ignored by one of your .gitignore files`, leaving half-finished `chore:` commits on HEAD and requiring a manual `git reset --hard` to recover. The path is a git subtree managed by BALDART — it MUST be tracked — and the failure mode was both confusing (the user never added `.framework` to ignore on purpose) and unfixable from inside the broken flow. v3.14.0 detects the collision and rewrites `.gitignore` idempotently at the top of every install / update / push, so a single `baldart` invocation always converges to a working state.
|
|
33
|
+
|
|
16
34
|
### Added
|
|
17
35
|
|
|
36
|
+
- **`GitUtils.checkFrameworkIgnored()` + `GitUtils.ensureFrameworkNotIgnored()`** in `src/utils/git.js` — central, idempotent self-heal for the `.framework/` ↔ `.gitignore` collision. `checkFrameworkIgnored` runs `git check-ignore -v --no-index -- .framework` and returns `{ ignored, source, line, pattern, raw }` (degrade-open: simple-git throws on non-zero exit, treated as "not ignored"). `ensureFrameworkNotIgnored` strips standalone `.framework` / `.framework/` / `/.framework` rules from the project `.gitignore`, appends a single negation block (`!.framework` + `!.framework/**`) with a marker comment so re-runs are no-ops, then re-runs the check and surfaces `stillIgnored` if a rule still wins from outside the repo (parent-dir `.gitignore`, exotic `core.excludesFile`). Returns `{ wasFixed, stillIgnored, removedLines, appendedNegation, source, pattern, recheck }`. Never throws — callers can safely wrap it in best-effort try/catch.
|
|
37
|
+
- **`baldart add` / `baldart update` / `baldart push` auto-heal `.gitignore`** — each command calls `ensureFrameworkNotIgnored()` at the top of its flow, before `git subtree add` / `git subtree pull` / any `git add` runs. Healing prints a yellow warning so the user sees what changed, then continues without prompting (purely local file rewrite, fully idempotent). If a rule outside the project still wins, the flow exits with a clear, actionable message instead of failing deep in the autofix step with the cryptic `paths are ignored` git error.
|
|
38
|
+
- **`baldart doctor` `.gitignore` diagnostic + `unignore-framework` action** — `detectState` populates `state.frameworkIgnored` with the same payload; the status table renders a yellow `.gitignore IGNORES .framework/ (<source>:<line>) — will be auto-healed` row when triggered, and the planner inserts an `autoOk: true` action that calls the same helper. So `baldart` (no-arg doctor mode) detects, reports, and self-heals in a single invocation. Backfills the heal for consumers predating v3.14.0 that hit the broken-push state.
|
|
18
39
|
- **`claudePluginId()` returns real plugin ids** in every LSP adapter (`src/utils/lsp-adapters/{typescript,python,go,rust,ruby}.js`). Previously a `null` placeholder; now resolves to `typescript-lsp@claude-plugins-official`, `pyright-lsp@claude-plugins-official`, `gopls-lsp@claude-plugins-official`, `rust-analyzer-lsp@claude-plugins-official`, `ruby-lsp@claude-plugins-official` respectively. All plugins live in the Anthropic-published [`anthropics/claude-plugins-official`](https://github.com/anthropics/claude-plugins-official) marketplace.
|
|
19
40
|
- **`LspInstaller.installClaudePlugins(serverNames, opts)`** in `src/utils/lsp-installer.js` — high-level installer that (1) verifies the `claude` CLI is on PATH, (2) idempotently registers the `claude-plugins-official` marketplace via `claude plugin marketplace add anthropics/claude-plugins-official --scope user` (no-op when already registered — list is parsed first), (3) reads `claude plugin list --json` to skip plugins already installed at any scope, (4) runs `claude plugin install <id> --scope user` per missing plugin. Defaults to `--scope user` so a single install is reused across every project on the machine (LSP plugins are machine-wide useful — project scope would create N copies). Always returns `{ installed, skipped, manual, marketplace }`; never throws.
|
|
20
41
|
- **`LspInstaller.ensureClaudeMarketplace()`, `isClaudeCliAvailable()`, `listInstalledClaudePlugins()`, `verifyClaudePlugins(serverNames)`** — supporting primitives, all idempotent and degrade-open (parsing failure returns empty set → next install is attempted rather than incorrectly skipped).
|
|
@@ -32,21 +53,9 @@ Since v3.10.0, opting into `features.has_lsp_layer: true` installed the language
|
|
|
32
53
|
- **Marketplace and plugins live at `--scope user`, not project.** Three reasons: (1) LSP plugins are machine-wide useful — typescript-lsp installed once at user scope is reused by every TS project on the machine, not duplicated N times; (2) marketplace install at user scope means subsequent `baldart configure` runs in sibling projects skip the marketplace add entirely (idempotent); (3) project-scope plugins live under `.claude/` in the consumer repo, which would either need committing (noisy diffs) or `.gitignore` adjustments (extra protocol burden). User scope avoids all three.
|
|
33
54
|
- **Idempotency is checked twice.** Marketplace add reads `claude plugin marketplace list --json` first; plugin install reads `claude plugin list --json` first. Re-running `baldart configure` (or `baldart doctor` with the action accepted) is a no-op when everything is in place — no spurious install commands, no error noise.
|
|
34
55
|
- **Gate on `claude` in `tools.enabled`.** When the consumer has `tools.enabled: [codex]` (Codex-only), the plugin install is a silent no-op — Codex has no equivalent plugin model and Claude marketplace mutation would be off-target. Doctor diagnostics for missing plugins are similarly gated.
|
|
35
|
-
- **No framework payload changes.** All work is inside `src/` — adapters, installer, configure command, doctor command
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`.framework/` is a git subtree — it MUST be tracked. If anything in the gitignore chain (project `.gitignore`, `.git/info/exclude`, global `core.excludesFile`) matches `.framework`, every subsequent `git add` on files under that directory fails with `paths are ignored by one of your .gitignore files` — and `git subtree pull` itself errors out. Pre-v3.14.0 we relied on the user noticing and removing the rule manually; v3.14.0 detects and self-heals.
|
|
40
|
-
|
|
41
|
-
### Added
|
|
42
|
-
|
|
43
|
-
- **`GitUtils.checkFrameworkIgnored()` and `ensureFrameworkNotIgnored()`** in `src/utils/git.js` — `check-ignore -v --no-index .framework` to detect the offending source / line / pattern, then idempotently strip standalone `.framework` rules from the project `.gitignore` and append a one-time `!.framework` + `!.framework/**` negation block marked with `# BALDART: .framework/ is a git subtree — never ignore (auto-managed)`. Re-checks after writing — if the rule lives in a location we cannot rewrite from here (parent-dir `.gitignore` outside the repo, non-standard `core.excludesFile`), surfaces the leftover state via `{ stillIgnored: true, recheck }` so the caller can hard-fail with actionable output.
|
|
44
|
-
- **Self-heal call in `baldart add`** (before `git subtree add`), **`baldart update`** (before `git subtree pull`), **`baldart push`** (before any `git add`). All three flows degrade gracefully — if `check-ignore` itself fails, the heal step prints a warning and continues; if the rule persists after heal, the command exits 1 with the resolution path printed.
|
|
45
|
-
|
|
46
|
-
### Notes (gitignore)
|
|
47
|
-
|
|
48
|
-
- **Idempotent across re-runs.** The negation marker is checked before appending; the strip step is a `filter` over current lines. Running `add` / `update` / `push` repeatedly on a healthy repo is a no-op.
|
|
49
|
-
- **No false positives on .framework-related paths.** The strip filter matches only the six exact forms (`.framework`, `.framework/`, `/.framework`, `/.framework/`, `.framework/*`, `/.framework/*`) — `.frameworks/` or `framework/something.bak` patterns are preserved untouched.
|
|
56
|
+
- **No framework payload changes.** All work is inside `src/` — adapters, installer, configure command, doctor command, and `GitUtils`. No framework agent/skill/command/protocol module touched, so existing consumers see the new behavior the next time they run `baldart configure` or `baldart doctor` after upgrading the CLI (`npm i -g baldart@latest`).
|
|
57
|
+
- **`.gitignore` heal is idempotent across re-runs.** The negation marker is checked before appending; the strip step is a `filter` over current lines. Running `add` / `update` / `push` repeatedly on a healthy repo is a no-op (the negation block is added once, future calls match the marker and skip).
|
|
58
|
+
- **`.gitignore` heal has no false positives.** The strip filter matches only the exact forms (`.framework`, `.framework/`, `/.framework`, `/.framework/`, `.framework/*`, `/.framework/*`) — `.frameworks/` or `framework/something.bak` patterns are preserved untouched.
|
|
50
59
|
|
|
51
60
|
## [3.13.0] - 2026-05-23
|
|
52
61
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.14.
|
|
1
|
+
3.14.1
|
package/package.json
CHANGED
package/src/utils/git.js
CHANGED
|
@@ -198,11 +198,16 @@ class GitUtils {
|
|
|
198
198
|
if (!line) return { ignored: false };
|
|
199
199
|
// Format: "<source>:<line>:<pattern>\t<path>"
|
|
200
200
|
const m = /^(.+?):(\d+):([^\t]+)\t/.exec(line);
|
|
201
|
+
const pattern = m ? m[3] : null;
|
|
202
|
+
// A leading `!` makes it a NEGATION pattern — the path is re-included,
|
|
203
|
+
// not ignored. `git check-ignore` still prints it (matching != ignored).
|
|
204
|
+
const isNegation = pattern ? pattern.startsWith('!') : false;
|
|
205
|
+
if (isNegation) return { ignored: false, negatedBy: pattern };
|
|
201
206
|
return {
|
|
202
207
|
ignored: true,
|
|
203
208
|
source: m ? m[1] : 'unknown',
|
|
204
209
|
line: m ? Number(m[2]) : null,
|
|
205
|
-
pattern
|
|
210
|
+
pattern,
|
|
206
211
|
raw: line
|
|
207
212
|
};
|
|
208
213
|
} catch (_) {
|