Repository navigation
v3.21.2 - the installer now leaves your own git hooks working, and a junk value in a cloned repo's config no longer overrides your global off switches
The installer now leaves your own git hooks working, and a junk value in a cloned repo's config no longer overrides your global off switches.
Security
- CWK-158 item 1 + CWK-141 (1) — a project config value the clamp does not recognise is now dropped, not kept. The config cascade lets a cloned repo's
.coalmine.jsononly quieten what your global config sets. Before this fix, a project value outside a key's allowed set (null, a string such as"on", a number) was left in the merge as it was, and it replaced your global choice:{"rotCanaryMode": "on"},{"enableConductor": null}or{"updateMode": "x"}in a cloned repo defeated your globaloff, and{"disabledCanaries": null}(or a string or a number) replaced your global list. Now such a value reads as absent: your global value stands, or the factory default where your global layer says nothing. An unknown value in your GLOBAL file reads as the factory default. This coversupdateMode,enableConductor,rotCanaryMode,disabledCanariesandscanExcludePathsin the three hooks and in the PowerShell fallbacks (alt/powershell), where a JSONnullcounts as a present value and a non-boolean is never turned into a boolean.scanEverythingwas not affected (its stricttruecheck never accepted the string"true"); its row is kept as a control. — test:scripts/lib/hooks.test.mjs(clamp drops a junk project value (…), one row per key and shape) ·scripts/lib/conductor-update.test.mjs·scripts/lib/ps-config.test.ps1 - CWK-158 item 7 — install and uninstall no longer delete a folder only because an install manifest names it. A manifest (
.coalmine-manifest.json) can arrive with a cloned repository, and a folder it listed, such asvictim-dir, was removed recursively. A listed folder is now removed only when every file in it is recorded in the manifest's own hashes with the hash it has today. An unrecorded file, a changed file or a link makes it unproven: the installer prints[kept] <folder>: …, leaves it in place and exits non-zero. A manifest from before the hashes existed proves ownership only by CoalMine's ownskill-meta.jsonmarker. — test:scripts/lib/install.test.mjs(CWK-158 item 7: …, three tests)
Changed
- CWK-158 item 2 — the git hook the installer writes into your repo is a small chain-only hook, not CoalMine's own repo gate. Before, the installer copied CoalMine's
.githooks/pre-commitand.githooks/pre-pushinto your repo. Those runscripts/verify.mjsandscripts/test.mjsof the project they sit in, which is a no-op in most projects and a surprise blocker in one that has such scripts, and your own hook was renamed aside and never ran again. The installed hook now runs the hook it replaced (kept beside it as<hook>.pre-coalmine, with its arguments and exit status passed through) and nothing else, so installing CoalMine never turns off a gate you had. A hook your repo tracks (core.hooksPathat a versioned directory such as.husky/or.githooks/) is not rewritten: the installer prints[refused] <hook>: …and exits non-zero, the same refusal uninstall already had. — test:scripts/lib/install.test.mjs(CWK-158 item 2: …, three tests)
Fixed
- CWK-158 item 3 — uninstall no longer restores a backed-up hook over a hook you wrote after installing. The restore put
<hook>.pre-coalmineback over whatever was at the hook path. It now does so only over a hook that is CoalMine's. If the hook there is yours (or unreadable), both files stay, the installer prints[kept] <hook>: …and exits non-zero, and you merge them. — test:scripts/lib/install.test.mjs(CWK-158 item 3: …) - CWK-158 item 4 — a
core.hooksPaththat starts with~now expands the way git expands it. The installer read the value as plain text, so~/hooksbecame<project>/~/hookswhile git ran$HOME/hooks: the hook landed in a folder git never reads. It now reads the value as a path (git config --type=path). If that git is too old for--typeand the value starts with~, the installer reports that it cannot expand it instead of guessing. — test:scripts/lib/install.test.mjs(CWK-158 item 4: …) - CWK-158 item 5 —
configure.mjsno longer anchors its project search on a legacy config in a folder above the one you ran it from, unless that folder is the git root. Its search used to stop at the first parent folder holding.claude/.coalmine.json, then move that file into the project's own config folder and delete the original. That legacy file now anchors the search only in the folder you ranconfigure.mjsfrom. A.gitfolder above still anchors it: run from a subfolder of a git project, a legacy config at the git root is still read and migrated, as before. The hooks' read order is unchanged. — test:scripts/lib/configure.test.mjs(CWK-158 item 5: …)
What you need to do: nothing is required, and if the installer printed a [refused] or [kept] line it left that file alone: read the line and decide. To receive the changed files, on Claude Code run claude plugin update coalmine@coalmine; users of coalmine@claude-community receive them when that catalog's pin moves; for any other agent, update your CoalMine checkout and re-run node scripts/install.mjs <agent>. If CoalMine's old gate hooks are already in a repo of yours, re-run the installer there to replace them with the chain-only hook.