@thebassclef/lite 1.9.3 → 1.9.4

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/README.md CHANGED
@@ -63,7 +63,7 @@ your browser.
63
63
 
64
64
  ## Current release
65
65
 
66
- <!-- version-start -->1.9.3<!-- version-end -->
66
+ <!-- version-start -->1.9.4<!-- version-end -->
67
67
 
68
68
  See [CHANGELOG.md](CHANGELOG.md) for the full changelog. Adopter-facing
69
69
  release notes live at [docs.bassclef.dev/docs/whats-new/releases](https://docs.bassclef.dev/docs/whats-new/releases).
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const version = "1.9.3";
3
+ const version = "1.9.4";
4
4
  exports.version = version;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version: "1.9.3";
1
+ export declare const version: "1.9.4";
2
2
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = "1.9.3";
1
+ const version = "1.9.4";
2
2
  export {
3
3
  version
4
4
  };
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "v1.5.2",
3
- "marker_tag": "release-2026-09-25-26328f36",
4
- "release_date": "2026-09-25T17:01:41Z",
5
- "release_sha": "26328f36",
6
- "release_tag": "release-2026-09-25-26328f36"
2
+ "version": "v1.6.0",
3
+ "marker_tag": "release-2026-09-26-db89d305",
4
+ "release_date": "2026-09-26T12:19:56Z",
5
+ "release_sha": "db89d305",
6
+ "release_tag": "release-2026-09-26-db89d305"
7
7
  }
@@ -8,14 +8,17 @@
8
8
  # file at $HOME/.claude/hooks/, not a symlink to a checkout).
9
9
  #
10
10
  # The resolver probes four paths in order per Chain-of-Responsibility:
11
- # 1. Peer-checkout — $CWD/../bassclef with sentinel file present
12
- # 2. $HOME/bassclef — tarball adopter path with sentinel file present
13
- # 3. Bundled path — walk up from $HOOK_REAL_PATH with sentinel present
11
+ # 1. Bundled path — walk up from $HOOK_REAL_PATH with sentinel present
12
+ # (was Check 3 pre-#1954; moved to Check 1 for #1953 shadow class cure —
13
+ # adopters with adjacent bassclef checkouts now get the npm install path)
14
+ # 2. Peer-checkout — $CWD/../bassclef with sentinel file present
15
+ # 3. $HOME/bassclef — tarball adopter path with sentinel file present
14
16
  # 4. Fallback — $CWD (adopter repo); safer than $HOME because the files
15
17
  # fragments want ship into the repo via bassclef init
16
18
  #
17
19
  # The sentinel file is presence/install/bassclef-hook-connect.sh. Every
18
20
  # probe requires it — an empty peer dir or empty $HOME/bassclef does NOT win.
21
+ # Nygard R1 fold — bundled probe fail-through preserves peer-checkout adopters.
19
22
  #
20
23
  # Silent contract: never crashes, never writes to stderr on the resolve path.
21
24
  # Consumers (13 fragments plus session-reflection.sh coordinator) treat the
@@ -42,17 +45,9 @@ resolve_bassclef_dir() {
42
45
  local home_dir="${HOME_OVERRIDE:-${HOME:-/nonexistent}}"
43
46
  local sentinel="presence/install/bassclef-hook-connect.sh"
44
47
 
45
- # 1. Peer-checkout — sibling bassclef dir next to $CWD
46
- if [ -d "$cwd/../bassclef" ] && [ -f "$cwd/../bassclef/$sentinel" ]; then
47
- ( cd "$cwd/../bassclef" 2>/dev/null && pwd ) && return 0
48
- fi
49
-
50
- # 2. $HOME/bassclef — tarball adopter path
51
- if [ -d "$home_dir/bassclef" ] && [ -f "$home_dir/bassclef/$sentinel" ]; then
52
- printf '%s\n' "$home_dir/bassclef" && return 0
53
- fi
54
-
55
- # 3. Bundled path — walk up two levels from dispatcher
48
+ # 1. Bundled path — walk up two levels from dispatcher (SWAPPED to Check 1
49
+ # per #1954 Layer 1a — closes #1953 shadow class where an adjacent
50
+ # bassclef checkout at $CWD/../bassclef was winning over the npm install).
56
51
  if [ -n "$hook_path" ]; then
57
52
  local candidate
58
53
  candidate="$( cd "$(dirname "$hook_path")/../.." 2>/dev/null && pwd )" || candidate=""
@@ -61,6 +56,17 @@ resolve_bassclef_dir() {
61
56
  fi
62
57
  fi
63
58
 
59
+ # 2. Peer-checkout — sibling bassclef dir next to $CWD (Nygard R1 fold —
60
+ # preserves peer-checkout adopters when bundled probe fails).
61
+ if [ -d "$cwd/../bassclef" ] && [ -f "$cwd/../bassclef/$sentinel" ]; then
62
+ ( cd "$cwd/../bassclef" 2>/dev/null && pwd ) && return 0
63
+ fi
64
+
65
+ # 3. $HOME/bassclef — tarball adopter path
66
+ if [ -d "$home_dir/bassclef" ] && [ -f "$home_dir/bassclef/$sentinel" ]; then
67
+ printf '%s\n' "$home_dir/bassclef" && return 0
68
+ fi
69
+
64
70
  # 4. Fallback — $CWD (adopter repo). Safer than $HOME because the files
65
71
  # fragments want (init manifest, presence/install/*) ship into the repo.
66
72
  ( cd "$cwd" 2>/dev/null && pwd ) || printf '%s\n' "$cwd"
@@ -241,13 +241,58 @@ bassclef_hook_connect_apply() {
241
241
  echo "[bassclef-hook-connect] no tier declared in .bassclef-source.json — merging all wires (grace window). Set tier: lite to filter." >&2
242
242
  fi
243
243
 
244
+ # === Filter-on-read (bassclef-upstream#1954) ===
245
+ # For each bassclef hook command, verify the target file exists at
246
+ # $bassclef_root/.claude/hooks/<basename>. Skip any entry whose target is
247
+ # missing. Log every skip to stderr. Emit warn banner over threshold.
248
+ # Saltzer-Schroeder R4 fold — matches both $CLAUDE_PROJECT_DIR- and
249
+ # $HOME-prefixed commands via basename extraction from .claude/hooks/ path.
250
+ # Nygard R2 mitigation — [ -f ] with symlink follow.
251
+ local present_re=""
252
+ local skip_count=0
253
+ local skipped_targets_file="$adopter_cwd/.bassclef-hook-connect-skipped.$$.tmp"
254
+ : > "$skipped_targets_file"
255
+ local present_basenames_file="$adopter_cwd/.bassclef-hook-connect-present.$$.tmp"
256
+ : > "$present_basenames_file"
257
+ local bhc_cmd bhc_base bhc_target
258
+ while IFS= read -r bhc_cmd; do
259
+ [ -z "$bhc_cmd" ] && continue
260
+ bhc_base=$(echo "$bhc_cmd" | grep -oE '\.claude/hooks/[^"'"'"'[:space:]\\]+\.sh' | head -1 | sed 's#\.claude/hooks/##')
261
+ if [ -z "$bhc_base" ]; then
262
+ continue
263
+ fi
264
+ bhc_target="$bassclef_root/.claude/hooks/$bhc_base"
265
+ if [ -f "$bhc_target" ] || [ -L "$bhc_target" ]; then
266
+ echo "$bhc_base" >> "$present_basenames_file"
267
+ else
268
+ echo "$bhc_target" >> "$skipped_targets_file"
269
+ skip_count=$((skip_count + 1))
270
+ echo "[bassclef-hook-connect] skip — target missing at $bhc_target" >&2
271
+ fi
272
+ done < <(jq -r '.hooks // {} | to_entries[] | .value[]? | .hooks[]? | .command // empty' "$bassclef_settings" 2>/dev/null)
273
+
274
+ if [ -s "$present_basenames_file" ]; then
275
+ present_re=$(sort -u "$present_basenames_file" | sed 's/\.sh$//' | paste -sd'|' -)
276
+ fi
277
+
278
+ # Warn banner over threshold. Threshold=0 disables banner but per-skip
279
+ # stderr above still fires.
280
+ local warn_threshold="${BASSCLEF_HOOK_CONNECT_SKIP_WARN:-5}"
281
+ if [ "$skip_count" -gt 0 ] && [ "$warn_threshold" -gt 0 ] && [ "$skip_count" -gt "$warn_threshold" ]; then
282
+ echo "[bassclef-hook-connect] WARN — $skip_count entries skipped (target files missing). Top 3:" >&2
283
+ sort -u "$skipped_targets_file" | head -3 | sed 's/^/ - /' >&2
284
+ echo " Set BASSCLEF_HOOK_CONNECT_SKIP_WARN=N to change threshold, or 0 to disable banner." >&2
285
+ fi
286
+ rm -f "$present_basenames_file" "$skipped_targets_file"
287
+
244
288
  # Merge every hook entry from every event type. Preserves operator-owned
245
289
  # entries. Adds bassclef entries under matching (event, matcher) pairs
246
290
  # without duplicating commands. Skips Lane 3 hooks at $CLAUDE_PROJECT_DIR
247
291
  # per <consumer-repo>#1262. Filters off-tier entries when tier_re non-empty
248
- # per bassclef-upstream#1946.
292
+ # per bassclef-upstream#1946. Filters missing-target entries when
293
+ # present_re non-empty per bassclef-upstream#1954.
249
294
  local merged
250
- merged=$(jq --slurpfile bassclef "$bassclef_settings" --arg lane3re "$lane3_re" --arg tierre "$tier_re" '
295
+ merged=$(jq --slurpfile bassclef "$bassclef_settings" --arg lane3re "$lane3_re" --arg tierre "$tier_re" --arg presentre "$present_re" '
251
296
  . as $adopter
252
297
  | ($bassclef[0].hooks // {}) as $bhooks
253
298
  | .hooks //= {}
@@ -264,6 +309,15 @@ bassclef_hook_connect_apply() {
264
309
  # tier manifest set. Empty tier_re means no filter (fallback).
265
310
  ($tierre == "") or
266
311
  ((.command // "") | test("\\.claude/hooks/(" + $tierre + ")\\.sh"))
312
+ )) | map(select(
313
+ # Filter-on-read (bassclef-upstream#1954): keep only entries whose
314
+ # target hook file exists at $bassclef_root/.claude/hooks/<basename>.
315
+ # Empty present_re means no filter (fallback merge-all — matches
316
+ # the tier filter fallback shape). Non-.claude/hooks commands pass
317
+ # through (not our target class).
318
+ ($presentre == "") or
319
+ ((.command // "") | test("\\.claude/hooks/[a-zA-Z0-9._-]+\\.sh") | not) or
320
+ ((.command // "") | test("\\.claude/hooks/(" + $presentre + ")\\.sh"))
267
321
  ))) as $bhookslist |
268
322
  if ($bhookslist | length) == 0 then .
269
323
  elif any(.hooks[$event][]; (.matcher // "") == $bmatcher) then
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tier": "lite",
3
- "manifest_version": "1.11.1",
4
- "generated_at": "2026-09-25T15:57:21Z",
3
+ "manifest_version": "1.11.2",
4
+ "generated_at": "2026-09-26T11:18:11Z",
5
5
  "entries": [
6
6
  {
7
7
  "slug": "029-release-pipeline",
@@ -736,7 +736,7 @@
736
736
  "type": "lib",
737
737
  "path": "lib/bassclef-dir-resolver.sh",
738
738
  "tier": "lite",
739
- "content_hash": "sha256:10d42c54a64415f7e9b4f2a6701d57ffc89cc9d59ec0fec9ddc2af3c178855a2",
739
+ "content_hash": "sha256:7b0f95e282983cca1edcf27083526edabc964e72cd0ef3596c7c8df915e24f92",
740
740
  "description": "bassclef-dir-resolver.sh — resolve BASSCLEF_DIR across install layouts."
741
741
  },
742
742
  {
@@ -1303,7 +1303,7 @@
1303
1303
  "type": "presence-template",
1304
1304
  "path": "presence/install/bassclef-hook-connect.sh",
1305
1305
  "tier": "lite",
1306
- "content_hash": "sha256:7ac3148028a5f2fd1ca35b84812c664d2ff10b475026f278c78c490f6b12fa21",
1306
+ "content_hash": "sha256:a50c3ca715f4f786e2bcbbd804923711f34fe29924aa7a487808934612993ec6",
1307
1307
  "description": "description: Dynamic-derive hook connect — closes bassclef-upstream#625."
1308
1308
  },
1309
1309
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thebassclef/lite",
3
- "version": "1.9.3",
3
+ "version": "1.9.4",
4
4
  "description": "Bassclef CLI — install and upgrade bassclef in your project with two commands.",
5
5
  "keywords": [
6
6
  "bassclef",