@thebassclef/lite 1.5.1 → 1.7.0

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.
@@ -131,7 +131,9 @@ done
131
131
  # Surface findings
132
132
  if [ "$ANY_BLOCKED" = "1" ]; then
133
133
  MSG="workflow-staleness — bassclef workflow(s) failed >${THRESHOLD_HOURS}h ago without recovery:\n$(echo -e "$DETAILS")\nThis is the silent-failure class WU-9d retires. Read the failed run logs (gh run view <id>); root-cause + fix or operator-confirm deferral. Do not silently ignore."
134
- blocked_banner "$MSG"
134
+ # Per standards/session-start-banner-discipline.md — ADVISORY: workflow is
135
+ # failing but the current session can proceed; operator should investigate.
136
+ blocked_banner "$MSG" advisory
135
137
  elif [ "$ANY_WARN" = "1" ]; then
136
138
  echo "### WORKFLOW-STALENESS — WARN (within ${THRESHOLD_HOURS}h grace)"
137
139
  echo ""
@@ -11,6 +11,27 @@
11
11
  # works cleanly both sourced AND standalone. Silent-fail on missing
12
12
  # manifest or missing jq.
13
13
 
14
+ # SELF_MODE guard per bassclef-upstream#1804 — hook manifest staleness only
15
+ # meaningful for adopters watching for hook churn; bassclef-upstream IS
16
+ # the source where new hooks land daily.
17
+ if [ "${SELF_MODE:-0}" = "1" ]; then
18
+ return 0 2>/dev/null || exit 0
19
+ fi
20
+
21
+ # Fresh-install gate (bassclef-upstream#1896): on cold adopter install,
22
+ # every hook file's mtime equals install time (recent). The last_manifest_update
23
+ # field is older by design (records when maintainer bumped it upstream). Result:
24
+ # every hook flags as "new not in manifest" — spurious BLOCKED banner on every
25
+ # lite adopter's first session. Cure: skip when no heartbeat markers exist
26
+ # (mirrors 80-hook-heartbeat-check.sh cold-install gate #1818 Ship 3). The gate
27
+ # activates the moment a producer hook fires and writes its first marker.
28
+ # Anchor: @luminary donald-norman — banner fires only when a real problem
29
+ # exists. @luminary michael-feathers — cold-install mtime is characterization
30
+ # baseline; comparing against it produces false positives.
31
+ if [ ! -d "state/markers/hook-heartbeat" ]; then
32
+ return 0 2>/dev/null || exit 0
33
+ fi
34
+
14
35
  # Probe bundled path first (dist/lite/ ship path per ADR-056 D3), then
15
36
  # $BASSCLEF_DIR fallback for synced adopters. Pattern matches
16
37
  # session-reflection.sh:11-17. Cures #1732 Phase A silent-fail at operator
@@ -111,21 +111,24 @@ while IFS= read -r __shv_file; do
111
111
  done <<< "$__shv_settings_files"
112
112
 
113
113
  if [ -n "$__shv_missing" ]; then
114
- blocked_banner "settings-hook-verify" \
115
- "Hooks wired in settings.json but missing on disk:" \
116
- "$__shv_missing" \
117
- "" \
118
- "Cure paths:" \
119
- " 1. Re-run bassclef-sync.sh to restore vendored/symlinked hooks" \
120
- " 2. Edit the settings file and remove the stale entry" \
121
- " 3. Override this session: SKIP_SETTINGS_HOOK_VERIFY=1" \
122
- "" \
123
- "Per bassclef-upstream#888."
114
+ # Compose one $msg per blocked_banner (msg, severity?) signature.
115
+ # Prior code passed 10 args; args 3-9 silently dropped because banner
116
+ # takes only msg + optional severity. Per bassclef-upstream#1897.
117
+ __shv_msg="Hooks wired in settings.json but missing on disk:
118
+ $__shv_missing
119
+
120
+ Cure paths:
121
+ 1. Re-run bassclef-sync.sh to restore vendored/symlinked hooks
122
+ 2. Edit the settings file and remove the stale entry
123
+ 3. Override this session: SKIP_SETTINGS_HOOK_VERIFY=1
124
+
125
+ Per bassclef-upstream#888."
126
+ blocked_banner "$__shv_msg"
124
127
  trace_log "fired" "settings-hook-verify" "missing hooks detected" 2>/dev/null || true
125
128
  else
126
129
  trace_log "pass" "settings-hook-verify" "all wired hooks resolve" 2>/dev/null || true
127
130
  fi
128
131
 
129
132
  unset __shv_settings_files __shv_project_settings __shv_user_settings \
130
- __shv_missing __shv_file
133
+ __shv_missing __shv_file __shv_msg
131
134
  unset -f __shv_check_file __shv_scan_settings
@@ -85,20 +85,29 @@ blocked_banner() {
85
85
  local msg="$1"
86
86
  local severity="${2:-blocking}"
87
87
  echo ""
88
- if [ "$severity" = "advisory" ]; then
89
- echo "NOTE"
90
- echo "────────────────────────────────────────────"
91
- echo "$msg"
92
- echo "────────────────────────────────────────────"
93
- echo "Worth doing. Not blocking this session."
94
- else
95
- echo "🛑🛑🛑 BLOCKED 🛑🛑🛑"
96
- echo "────────────────────────────────────────────"
97
- echo "$msg"
98
- echo "────────────────────────────────────────────"
99
- echo "ACTION: resolve OR explicitly defer (per .claude/rules/blocked-items.md)."
100
- echo "Silence is not deferral. Propose this as item #1 in your session plan."
101
- fi
88
+ case "$severity" in
89
+ info)
90
+ echo "ℹ INFO"
91
+ echo "────────────────────────────────────────────"
92
+ echo "$msg"
93
+ echo "────────────────────────────────────────────"
94
+ ;;
95
+ advisory)
96
+ echo "⚠ ADVISORY"
97
+ echo "────────────────────────────────────────────"
98
+ echo "$msg"
99
+ echo "────────────────────────────────────────────"
100
+ echo "Worth reading. Not blocking this session."
101
+ ;;
102
+ blocking|*)
103
+ echo "🛑🛑🛑 BLOCKED 🛑🛑🛑"
104
+ echo "────────────────────────────────────────────"
105
+ echo "$msg"
106
+ echo "────────────────────────────────────────────"
107
+ echo "ACTION: resolve OR explicitly defer (per .claude/rules/blocked-items.md)."
108
+ echo "Silence is not deferral. Propose this as item #1 in your session plan."
109
+ ;;
110
+ esac
102
111
  echo ""
103
112
  }
104
113
 
@@ -13,21 +13,33 @@ This rule is the methodology layer. The mechanism is the /longrun SKILL body Ste
13
13
 
14
14
  Every `/longrun prep` dispatch. The SKILL body Step 0.85 checks for a plan doc first. When one is found, the compressed prep path fires (converged preset). When none matches, prep falls to exploratory or reversible-small per the picker.
15
15
 
16
- Detection criteria for the converged preset (all three must match):
16
+ Detection fires from three signal sources. The picker checks in precedence order:
17
+
18
+ **Signal 1 — plan doc present + fresh** (all three must match):
17
19
 
18
20
  1. File matching `docs/next-session-plan-*.md` exists at repo root
19
21
  2. File was modified within the last 48 hours (`find -mtime -2`)
20
22
  3. File body contains one of: `## Recommended session sequence`, `## Recommended sequence`, `## Next-session pickup`
21
23
 
24
+ **Signal 2 — fresh /state-a-problem marker** (`state/markers/state-a-problem/` `-mtime -2`).
25
+
26
+ **Signal 3 — whereami PRIMARY queue** (per Q1 /longrun 2026-09-22 Step 1):
27
+
28
+ 1. `docs/whereami.md` carries a `next_in_flight_goal:` line
29
+ 2. That line (or its continuation within 10 lines) names PRIMARY candidates in priority order (numbered `(1)`, `(2)` OR the phrase `priority order`)
30
+ 3. No unresolved `GATE` line sits above the PRIMARY list (a `GATE — wait for X` inside the same block blocks converged)
31
+
32
+ Precedence — plan doc wins over problem marker; problem marker wins over whereami PRIMARY. The mechanical helper at `scripts/longrun-preset-detect.sh` encodes this precedence. Test coverage at `scripts/tests/longrun-preset-detect.test.sh` (15 Tier 0 tests).
33
+
22
34
  ## The three presets (per bassclef-upstream#1598)
23
35
 
24
36
  Per `.claude/skills/longrun/SKILL.md` Step 0.85 picker. Prep renders in the shape that fits the mode:
25
37
 
26
38
  | Preset | Fires when | Shape |
27
39
  |---|---|---|
28
- | **converged** | Plan doc matches criteria above OR fresh `/state-a-problem` marker present | Lean canvas — Problem + Value + Solution + options table |
29
- | **exploratory** | No plan doc + operator typed `/longrun` alone + no fresh problem marker | Scan-table dominant — options table + one line per row + recommend row marker |
30
- | **reversible-small** | Small scope stated in the invocation + won't break other work | Three-chunk compact — one line per option, one recommend line, one action line |
40
+ | **converged** | Any of the three signals above fires (plan doc OR problem marker OR whereami PRIMARY) | Lean canvas — Problem + Value + Solution + options table |
41
+ | **exploratory** | No signal fires; operator typed `/longrun` alone | Scan-table dominant — options table + one line per row + recommend row marker |
42
+ | **reversible-small** | Small scope stated in the invocation + will not break other work | Three-chunk compact — one line per option, one recommend line, one action line |
31
43
 
32
44
  Ambiguous cases: picker asks `Converged / Exploratory / Small? (c/e/s/skip)`.
33
45
 
@@ -72,6 +84,13 @@ INSTEAD of overriding routinely: update the plan doc. A stale plan doc is a bad
72
84
  - `.claude/rules/plan-enumeration-needs-value-props.md` — every option in the compressed scan-table still carries a value-prop cell
73
85
  - `.claude/rules/blocked-items.md` — silence is not deferral (plan doc detection reports fire vs skip explicitly)
74
86
  - `.claude/rules/bootstrap-pair-discipline.md` — this rule + SKILL amendment ship as paired bootstrap
75
- - @luminary john-ousterhoutdeep module (compression path hides plan-doc detection behind narrow interface)
76
- - @luminary donald-normansignifier + feedback (plan doc presence is a signifier; compressed vs full ceremony is user feedback)
87
+ - `scripts/longrun-preset-detect.sh`mechanical detection helper (added Q1 /longrun 2026-09-22 Step 1)
88
+ - `scripts/tests/longrun-preset-detect.test.sh`Tier 0 test coverage (15 tests) pinning helper behavior
89
+ - `docs/use-cases/UC-rule-longrun-prep-whereami-signal.md` — brief use case for whereami PRIMARY signal
90
+ - @luminary john-ousterhout — deep module (compression path hides detection behind narrow helper interface)
91
+ - @luminary david-parnas — information hiding (rule cites helper; SKILL sources helper; logic in one place)
92
+ - @luminary tony-hoare — pre/postcondition contract (helper input: 3 optional dirs; output: exactly one preset + trigger source)
93
+ - @luminary donald-norman — signifier + feedback (helper prints trigger source to stderr so operator sees which signal fired)
94
+ - @luminary michael-nygard — stability (explicit precedence: plan doc > problem marker > whereami PRIMARY)
95
+ - @luminary michael-feathers — characterization test (fixtures pin REAL whereami shape variants)
77
96
  - @luminary frederick-brooks — conceptual integrity (compression preserves the option-table + card + step-card shape; only volume shrinks)
@@ -228,5 +228,9 @@
228
228
  "$HOME/src/sunj-labs/bassclef/.claude/luminaries",
229
229
  "$HOME/src/sunj-labs/bassclef/.claude/agents"
230
230
  ],
231
- "$schema": "https://bassclef.sunj-labs/state-spine/v0/schemas/bassclef-wiring-manifest.schema.json"
231
+ "$schema": "https://bassclef.sunj-labs/state-spine/v0/schemas/bassclef-wiring-manifest.schema.json",
232
+ "statusLine": {
233
+ "type": "command",
234
+ "command": "bash ~/.claude/bassclef-statusline.sh"
235
+ }
232
236
  }
@@ -207,22 +207,39 @@ The helper stays advisory through 2026-10-31 per ADR-031. Old hooks and libs lan
207
207
 
208
208
  | Preset | Fires when | Rendered shape |
209
209
  |---|---|---|
210
- | **converged** | Plan doc newer than 48h + carries `## Recommended` section, OR fresh `/state-a-problem` marker present | Lean canvas — Problem + Value + Solution + options table + card on ask |
211
- | **exploratory** | No plan doc + operator typed `/longrun` alone + no fresh problem marker | Scan-table dominant — options table + one line per row + recommend row marker |
212
- | **reversible-small** | Small scope stated in the invocation + won't break other work | Three-chunk compact — one line per option, one recommend line, one action line |
210
+ | **converged** | Any of: plan doc newer than 48h + carries `## Recommended`; OR fresh `/state-a-problem` marker; OR whereami `next_in_flight_goal:` carries PRIMARY queue with no unresolved GATE above | Lean canvas — Problem + Value + Solution + options table + card on ask |
211
+ | **exploratory** | No plan doc + operator typed `/longrun` alone + no fresh problem marker + no whereami PRIMARY | Scan-table dominant — options table + one line per row + recommend row marker |
212
+ | **reversible-small** | Small scope stated in the invocation + will not break other work | Three-chunk compact — one line per option, one recommend line, one action line |
213
213
 
214
214
  Ambiguous cases: picker asks the operator directly — `Converged / Exploratory / Small? (c/e/s/skip)`.
215
215
 
216
- Detection commands:
216
+ Detection helper (per bassclef-upstream#1598 + Q1 /longrun 2026-09-22 Step 1). One call returns one preset. Trigger source goes to stderr.
217
217
 
218
218
  ```bash
219
- # Converged signal — plan doc present + fresh
219
+ bash scripts/longrun-preset-detect.sh \
220
+ --whereami docs/whereami.md \
221
+ --plan-doc-dir docs \
222
+ --problem-marker-dir state/markers/state-a-problem
223
+ ```
224
+
225
+ Helper stdout is one of: `converged`, `exploratory`, `reversible-small`, `ambiguous`. Helper stderr names the trigger: `trigger=plan-doc`, `trigger=problem-marker`, `trigger=whereami-PRIMARY`, or `trigger=none`.
226
+
227
+ Raw detection commands (still valid; the helper wraps these):
228
+
229
+ ```bash
230
+ # Signal 1 — plan doc present + fresh
220
231
  find docs -maxdepth 1 -name 'next-session-plan-*.md' -mtime -2 -type f 2>/dev/null | head -1
221
232
 
222
- # Fresh problem statement
233
+ # Signal 2 — fresh problem statement
223
234
  find state/markers/state-a-problem -type f -mtime -2 2>/dev/null | head -1
235
+
236
+ # Signal 3 — whereami PRIMARY queue (added 2026-09-22)
237
+ awk '/^next_in_flight_goal:/{flag=1; n=0} flag {print; n++; if (n>=10) flag=0}' docs/whereami.md \
238
+ | grep -iE 'primary' | grep -iE '\(1\)|priority order'
224
239
  ```
225
240
 
241
+ Precedence rule: plan doc wins over problem marker. Problem marker wins over whereami PRIMARY. The helper enforces this order.
242
+
226
243
  The picker writes the preset marker at `state/markers/longrun-preset/<branch>.marker`. Downstream Stop hook reads the marker + applies the per-preset axis set from `.claude/rules/compounding-sequence-fresh-analysis.md` § Per-preset axis sets.
227
244
 
228
245
  Converged preset triggers Step 0.75 shipped-state check first. When any recommended path lands SHIPPED, prep reshapes to exploratory automatically.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": "v1.2.0",
3
+ "marker_tag": "release-2026-09-22-a26d8936",
4
+ "release_date": "2026-09-22T11:04:29Z",
5
+ "release_sha": "a26d8936",
6
+ "release_tag": "release-2026-09-22-a26d8936"
7
+ }
@@ -1,12 +1,20 @@
1
1
  # Bassclef adopter .gitignore template
2
2
  # Ships via bassclef init from presence/dist-templates/.gitignore per goal 12e Step 3.
3
3
  #
4
+ # Substrate tracked-by-default policy (per bassclef-upstream#1691 Cure 3 Path A):
5
+ # Substrate files under .claude/hooks/, .claude/skills/, .claude/rules/,
6
+ # .claude/agents/, .claude/luminaries/ are NOT ignored here. Adopters
7
+ # commit them so `git stash -u` does not grab them and Stop hooks do
8
+ # not fail. See .claude/bassclef-orientation.md for the opt-out recipe
9
+ # if you prefer substrate gitignored.
10
+ #
4
11
  # Reasoning:
5
12
  # - state/markers/* — session-local telemetry (per feedback-marker-paths-real-files-not-symlinks memory)
6
13
  # - state/session-locks/ + state/session-timing/ — session-scoped ephemeral state
7
14
  # - state/tier-accounting/ + state/luminary-implementations/ — walker output; regenerated on demand
8
15
  # - dist/ — build output (per goal 12e Step 2 build-adopter-tree.sh)
9
16
  # - .claude/hooks/logs/ — hook trace logs (operator-only)
17
+ # - .claude/hooks/*.trace — hook trace output (operator-only)
10
18
  # - node_modules/ — universal
11
19
  # - .DS_Store — macOS metadata
12
20
  #
@@ -469,6 +469,29 @@ _classify_via_patterns_json() {
469
469
  return 1
470
470
  }
471
471
 
472
+ # === _install_pattern_classification (private helper for Layer 2) ===
473
+ # Reads classification_when_unwired for a given pattern name from the JSON.
474
+ # Returns 0 + emits label on success; returns 1 if pattern missing or JSON
475
+ # not available. Enables Parnas info-hiding — each label lives as a
476
+ # grep-discoverable string in standards/hook-invocation-patterns.json
477
+ # instead of being algorithmically derived at runtime.
478
+ # Per bassclef-upstream#1880 — closes the doc-code drift class.
479
+ _install_pattern_classification() {
480
+ local candidate="${1:-}"
481
+ [ -z "$candidate" ] && return 1
482
+ local project_root="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
483
+ local patterns_json="$project_root/standards/hook-invocation-patterns.json"
484
+ [ -f "$patterns_json" ] || return 1
485
+ command -v jq >/dev/null 2>&1 || return 1
486
+ local label
487
+ label=$(jq -r --arg n "$candidate" '.patterns[] | select(.name == $n) | .classification_when_unwired' "$patterns_json" 2>/dev/null)
488
+ if [ -n "$label" ] && [ "$label" != "null" ]; then
489
+ echo "$label"
490
+ return 0
491
+ fi
492
+ return 1
493
+ }
494
+
472
495
  # === _install_pattern_is_valid (private helper for Layer 2) ===
473
496
  # Returns 0 if pattern is in the JSON pattern list OR in the hardcoded
474
497
  # fallback list (ci|launchd|lib|release|standard). Returns 1 otherwise.
@@ -556,10 +579,17 @@ classify_finding() {
556
579
  # Hook lives on disk but settings.json wiring absent.
557
580
  # If the hook is meant to live elsewhere (CI / launchd / sourced lib),
558
581
  # this is by design, not a failure.
559
- # Layer 2 (bassclef-upstream#1163)algorithmic label derivation:
560
- # "standard" DEAD-LETTER; anything else NOT-WIRED-BY-DESIGN-<UPPER>.
561
- # New patterns land in standards/hook-invocation-patterns.json; their
562
- # classification label flows through this branch without cascade edits.
582
+ # Layer 2 + bassclef-upstream#1880read classification_when_unwired
583
+ # from JSON so each label lives as a grep-discoverable string in
584
+ # standards/hook-invocation-patterns.json. Falls back to algorithmic
585
+ # derivation if JSON missing (defensive per @luminary michael-nygard).
586
+ local label
587
+ label=$(_install_pattern_classification "$install_pattern" 2>/dev/null)
588
+ if [ -n "$label" ]; then
589
+ echo "$label"
590
+ return 0
591
+ fi
592
+ # Fallback — hardcoded/algorithmic derivation when JSON unavailable
563
593
  if [ "$install_pattern" = "standard" ]; then
564
594
  echo "DEAD-LETTER"
565
595
  return 0
@@ -58,14 +58,41 @@ _sgw_init_cache() {
58
58
  # Extract every .sh literal ref from a shell file — the walker's resolve
59
59
  # step filters to only paths that map to real files, so false-positive
60
60
  # extractions are cheap.
61
+ #
62
+ # Post-filter (#1889): reject refs containing regex metacharacters —
63
+ # [^, \., .*, .+ — which appear when hooks grep for `.sh` patterns in
64
+ # other files. The suffix-fallback in _sgw_resolve_ref_in_repo would
65
+ # otherwise map these to phantom paths (e.g., `/[^/]+\.sh` resolves
66
+ # to a real hook via suffix extraction).
67
+ #
68
+ # NOT tightened to invocation-only extraction (`source X`/`bash X`)
69
+ # because many hooks assign paths to vars first, then invoke via the
70
+ # var later — `X_PATH="path/to/x.sh"; source "$X_PATH"`. The extractor
71
+ # would miss X_PATH's target line and the resolver could not follow.
72
+ # See docs/risk-ledgers/2026-09-21-source-graph-walker-tighten.md
73
+ # for the design decision to keep raw extraction + post-filter.
74
+ #
75
+ # Env-var escape: BASSCLEF_SGW_REGEX_FILTER=0 restores prior extractor
76
+ # behavior (no post-filter). For rescue when a real path contains a
77
+ # regex metacharacter (rare — paths never contain [^, \., .*, .+ in
78
+ # bassclef substrate).
61
79
  _sgw_extract_all_refs() {
62
80
  local file="$1"
81
+ local raw
63
82
 
64
83
  # 1. Every .sh literal in the file (quoted or path-shaped), from non-comment lines
65
- grep -vE '^[[:space:]]*#' "$file" 2>/dev/null | \
84
+ raw=$(grep -vE '^[[:space:]]*#' "$file" 2>/dev/null | \
66
85
  grep -oE '"[^"]+\.sh"|'"'"'[^'"'"']+\.sh'"'"'|\$\{[^}]+\}/[^"'"'"'[:space:]]+\.sh|[$][A-Za-z_][A-Za-z0-9_]*/[^"'"'"'[:space:]]+\.sh|(\./|\.\./|/)[^"'"'"'[:space:]$]+\.sh' 2>/dev/null | \
67
86
  tr -d '"'"'"'"' | \
68
- sort -u
87
+ sort -u)
88
+
89
+ # Post-filter (#1889) — drop refs with regex metacharacters.
90
+ # Escape via BASSCLEF_SGW_REGEX_FILTER=0.
91
+ if [ "${BASSCLEF_SGW_REGEX_FILTER:-1}" = "1" ] && [ -n "$raw" ]; then
92
+ echo "$raw" | grep -vE '\[\^|\\\.|\.\*|\.\+' 2>/dev/null || true
93
+ else
94
+ echo "$raw"
95
+ fi
69
96
 
70
97
  # 2. Glob-source patterns — for loops iterating dir/*.sh
71
98
  grep -oE 'for[[:space:]]+[[:alnum:]_]+[[:space:]]+in[[:space:]]+[^;$]+/\*\.sh' "$file" 2>/dev/null | \
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # tier: standard
3
+ # BASSCLEF_SYNC_VERSION=thin-pointer-statusline-2026-06-22
4
+ # ^^ DO NOT REMOVE — used by Surface 4 self-heal (migrate-adopter-references.sh)
5
+ # + bassclef-side drift check. Format: thin-pointer-statusline-YYYY-MM-DD.
6
+ #
7
+ # Thin-pointer bassclef statusline dispatcher.
8
+ #
9
+ # Source of truth for adopters' user-level statusline. Adopters install
10
+ # THIS file at ~/.claude/bassclef-statusline.sh; it finds bassclef's
11
+ # rich impl via sibling fast-path and exec's it on every tick. Substrate
12
+ # updates to the rich impl reach existing adopters because the pointer
13
+ # runs the live file, not a frozen copy.
14
+ #
15
+ # Three paths, tried in order (per #1860):
16
+ #
17
+ # 1. Sibling fast-path: $HOME/src/sunj-labs/bassclef OR /bassclef-upstream
18
+ # — if presence/cli/bassclef-statusline.sh exists and is executable,
19
+ # exec it with stdin piped through.
20
+ #
21
+ # 2. Script-relative: same directory as this dispatcher. Serves adopters
22
+ # who install only @thebassclef/lite via npm — the tarball ships both
23
+ # scripts side by side under node_modules/@thebassclef/lite/dist/lite/
24
+ # presence/cli/. Uses `cd $(dirname); pwd` for macOS + Linux portability
25
+ # (BSD readlink lacks -f per R15 rfc finding).
26
+ #
27
+ # 3. Fallback: minimal render so SessionStart doesn't crash. Adopter
28
+ # sees "bassclef · ?" instead of an empty statusline.
29
+ #
30
+ # Always exits 0 — same SessionStart-safe discipline as bassclef-sync
31
+ # dispatcher (per ADR-032).
32
+ #
33
+ # Versioning:
34
+ # thin-pointer-statusline-2026-06-22 — initial. Bump format when the
35
+ # dispatcher's contract changes (rare; ideally never).
36
+ #
37
+ # Primary lens: Linus — substrate carries the recovery cost. Adopters
38
+ # don't re-install when the rich impl evolves; the dispatcher's
39
+ # stability is what shields them.
40
+ #
41
+ # Anchor: Hyrum — the version string IS the observable surface adopters
42
+ # can grep to detect drift. Surface 4 self-heal in
43
+ # migrate-adopter-references.sh uses it.
44
+
45
+ set -u
46
+
47
+ __bassclef_statusline_version() {
48
+ echo "thin-pointer-statusline-2026-06-22"
49
+ }
50
+
51
+ # Read all of stdin so we can pipe it through to the rich impl
52
+ INPUT=$(cat 2>/dev/null || echo "{}")
53
+
54
+ # Resolve this dispatcher's directory for the script-relative fallback.
55
+ # `cd $(dirname); pwd` is portable across macOS (BSD readlink lacks -f) and
56
+ # Linux (GNU readlink -f works but we don't need it).
57
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
58
+
59
+ # Find rich impl via sibling fast-path, then script-relative fallback
60
+ RICH_IMPL=""
61
+ for CANDIDATE in \
62
+ "$HOME/src/sunj-labs/bassclef/presence/cli/bassclef-statusline.sh" \
63
+ "$HOME/src/sunj-labs/bassclef-upstream/presence/cli/bassclef-statusline.sh" \
64
+ "$SCRIPT_DIR/bassclef-statusline.sh"; do
65
+ if [ -x "$CANDIDATE" ]; then
66
+ RICH_IMPL="$CANDIDATE"
67
+ break
68
+ fi
69
+ done
70
+
71
+ if [ -n "$RICH_IMPL" ]; then
72
+ echo "$INPUT" | bash "$RICH_IMPL"
73
+ exit 0
74
+ fi
75
+
76
+ # Fallback — minimal render when no sibling is available
77
+ echo "bassclef · ?"
78
+ exit 0
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # tier: standard
3
+ # bassclef — Claude Code status line.
4
+ # Claude Code pipes session JSON on stdin every tick; whatever we print to stdout
5
+ # becomes the status line (ANSI colors allowed). Requires accepting the workspace
6
+ # trust prompt, same as any shell-executing setting. Keep it ONE short line.
7
+ #
8
+ # Register it in ~/.claude/settings.json — see bassclef-settings.snippet.json.
9
+ # Test: echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/x/bassline"},"context_window":{"used_percentage":23}}' | bash bassclef-statusline.sh
10
+
11
+ # Script-relative dir for tarball-layout fallback (#1860). Portable across
12
+ # macOS + Linux — `cd $(dirname); pwd` avoids BSD readlink -f gap. Python
13
+ # picks this up via os.environ; we cannot use __file__ under python3 -c.
14
+ BASSCLEF_STATUSLINE_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ export BASSCLEF_STATUSLINE_SCRIPT_DIR
16
+
17
+ python3 -c '
18
+ import sys, json, os
19
+ try:
20
+ d = json.load(sys.stdin)
21
+ except Exception:
22
+ d = {}
23
+ model = d.get("model", {}).get("display_name", "?")
24
+ cwd = d.get("workspace", {}).get("current_dir") or d.get("cwd", "")
25
+ base = os.path.basename(cwd.rstrip("/")) or "~"
26
+ pct = d.get("context_window", {}).get("used_percentage")
27
+
28
+ # Bassclef version segment (bet 2026-07-09d WU-1 / sunj-labs/bassclef-upstream#686).
29
+ # Reads bassclef-version.json. Fallback chain: env var, workspace root,
30
+ # peer sibling ../bassclef/. Prefers .version, falls back to .release_tag.
31
+ # Silent on any failure.
32
+ def read_bassclef_version(cwd):
33
+ def try_file(path):
34
+ if not path or not os.path.isfile(path):
35
+ return None
36
+ try:
37
+ with open(path) as f:
38
+ data = json.load(f)
39
+ except Exception:
40
+ return None
41
+ v = data.get("version") or data.get("release_tag")
42
+ return v if v else None
43
+ candidates = []
44
+ env_path = os.environ.get("BASSCLEF_VERSION_FILE")
45
+ if env_path:
46
+ candidates.append(env_path)
47
+ if cwd:
48
+ candidates.append(os.path.join(cwd, "bassclef-version.json"))
49
+ candidates.append(os.path.join(cwd, "..", "bassclef", "bassclef-version.json"))
50
+ # Script-relative tarball-layout fallback (#1860). Adopters installing
51
+ # only @thebassclef/lite via npm land under node_modules/@thebassclef/
52
+ # lite/dist/lite/presence/cli/, with bassclef-version.json two dirs up
53
+ # at dist/lite/bassclef-version.json. Runs LAST — cwd + peer sibling
54
+ # still win for adopters with a cloned repo (order per R16 rfc finding).
55
+ script_dir = os.environ.get("BASSCLEF_STATUSLINE_SCRIPT_DIR")
56
+ if script_dir:
57
+ candidates.append(os.path.join(script_dir, "..", "..", "bassclef-version.json"))
58
+ for p in candidates:
59
+ v = try_file(p)
60
+ if v:
61
+ return v
62
+ return None
63
+
64
+ version = read_bassclef_version(cwd)
65
+
66
+ O = "\033[38;2;232;93;4m" # burnt orange
67
+ C = "\033[38;2;205;201;189m"# cream
68
+ D = "\033[2m" # dim
69
+ R = "\033[0m"
70
+ sep = " " + D + "\u00b7" + R + " " # dim middot
71
+
72
+ seg = [O + "\U0001D122 bassclef.dev" + R, C + model + R, D + base + R]
73
+ if version:
74
+ seg.append(D + version + R)
75
+ if pct is not None:
76
+ seg.append(D + str(pct) + "%" + R)
77
+ sys.stdout.write(sep.join(seg))
78
+ '
@@ -34,6 +34,47 @@ Every entry stays in this file for the life of the manifest. Never pruned. When
34
34
 
35
35
  ## Entries (newest first)
36
36
 
37
+ ### Q1 /longrun Slice D — session-start banner-tone discipline (v1.9.10 → v1.9.11, 2026-09-22)
38
+
39
+ - **Change type:** content-add (1 new standard) + content-change (session-reflection.sh + 3 fragments)
40
+ - **Fields:** 431 entries (up from 430). New standard `session-start-banner-discipline`. Content hashes shift on `session-reflection.sh` + 3 exemplar fragments.
41
+ - **Version bump:** v1.9.10 → v1.9.11 (patch; entry added + content-hash changes; no schema shape shift).
42
+ - **Rationale:** bassclef-upstream#1704 Norman + Cooper consult. `blocked_banner` extended to 3-severity palette (info / advisory / blocking). 3 exemplar fragments migrated to advisory tone so Sam's first-run reads context not "broken install."
43
+ - **Downstream cure:** none owed. Existing 27 `blocked_banner` callers keep default `blocking` behavior; adopters see no change unless they update fragments.
44
+
45
+ ### Q1 /longrun Slice C — adopter git safety docs + tracked-by-default policy (v1.9.9 → v1.9.10, 2026-09-22)
46
+
47
+ - **Change type:** content-change (1 content hash; no entries added or removed)
48
+ - **Fields:** none changed. 430 entries before and after. One `content_hash` value moves — `.claude/bassclef-orientation.md`.
49
+ - **Version bump:** v1.9.9 → v1.9.10 (patch; content-hash change only; no schema shape shift).
50
+ - **Rationale:** bassclef-upstream#1691 Cure 2 + Cure 3 Path A. Orientation.md gains a "Substrate git posture" section explaining tracked-by-default plus a `git stash -u` footgun bullet and adopter opt-out recipe. The `presence/dist-templates/.gitignore` already permits substrate tracking; Slice C confirms with an inline comment naming the policy. No file removal or rewrite. Adopters see zero behavior change unless they read the new section.
51
+ - **Downstream cure:** none owed for adopters. Content-only change; adopters get the docs update via next `bassclef-sync`. Adopter opt-out recipe is documented for the small subset who prefer substrate gitignored.
52
+
53
+ ### Q1 /longrun Slice A — 81-hook-manifest-staleness fresh-install gate (v1.9.8 → v1.9.9, 2026-09-22)
54
+
55
+ - **Change type:** content-change (1 content hash; no entries added or removed)
56
+ - **Fields:** none changed. 430 entries before and after. One `content_hash` value moves — `hook/81-hook-manifest-staleness`.
57
+ - **Version bump:** v1.9.8 → v1.9.9 (patch; content-hash change only; no schema shape shift).
58
+ - **Rationale:** bassclef-upstream#1896 cure. Cold adopter install produces mtime = install time on every hook. `81-hook-manifest-staleness.sh` compared each hook's mtime to `last_manifest_update` field, flagging every hook as "new not in manifest" on cold install. Added fresh-install gate mirroring `80-hook-heartbeat-check.sh` L39-41 pattern per #1818 Ship 3. Sister SELF_MODE guard also added per #1804 pattern.
59
+ - **Downstream cure:** none owed for adopters. Content-only change; adopters get the fixed hook via next `bassclef-sync`.
60
+
61
+ ### Q1 /longrun Slice B — settings-hook-verify blocked_banner caller cure (v1.9.7 → v1.9.8, 2026-09-22)
62
+
63
+ - **Change type:** content-change (1 content hash; no entries added or removed)
64
+ - **Fields:** none changed. 430 entries before and after. One `content_hash` value moves — `hook/95-settings-hook-verify`.
65
+ - **Version bump:** v1.9.7 → v1.9.8 (patch; content-hash change only; no schema shape shift).
66
+ - **Rationale:** bassclef-upstream#1897 caller-side cure. `.claude/hooks/session-reflection.d/95-settings-hook-verify.sh` L114-125 rewritten so the 10-arg blocked_banner call serializes into one `$msg` body per the (msg, severity?) signature at `.claude/hooks/session-reflection.sh` L84. Missing-hooks list now surfaces at session-start banner instead of dropping silently. Deep tier-template cure defers to #1901 follow-on.
67
+ - **Downstream cure:** none owed for adopters. Content-only change; adopters get the fixed hook via next `bassclef-sync`.
68
+
69
+ ### Q1 /longrun Step 1 — /longrun Step 0.85 whereami PRIMARY signal (v1.9.6 → v1.9.7, 2026-09-22)
70
+
71
+ - **Change type:** content-change (2 content hashes; no entries added or removed)
72
+ - **Fields:** none changed. 430 entries before and after. Two `content_hash` values move — `rule/longrun-prep-plan-doc-compression` and `skill/longrun`.
73
+ - **Version bump:** v1.9.6 → v1.9.7 (patch; content-hash change only; no schema shape shift, no entry count change).
74
+ - **Rationale:** bassclef-upstream#1598 extension. `/longrun` Step 0.85 preset picker gains a third converged signal — whereami `next_in_flight_goal:` PRIMARY queue with no unresolved GATE. Rule and SKILL body now cite the new mechanical helper at `scripts/longrun-preset-detect.sh`. Rule adds 4 anchor luminaries. SKILL Step 0.85 detection block adds helper invocation + raw command for signal 3 + precedence note.
75
+ - **Downstream cure:** none. Patch bump; adopters on sync pick it up at the next `bassclef-sync`. The new helper lives at `scripts/longrun-preset-detect.sh` (tier upstream) — adopters do not receive it, only the rule + SKILL prose that cites it.
76
+ - **Old shape retired:** none.
77
+
37
78
  ### Ship 1 — install-class boundary + retag rollout (v1.8.7 → v1.9.0, 2026-09-20)
38
79
 
39
80
  - **Change type:** entry-removal (3 entries drop) + entry-add (1 template ships) + policy-change (Gate B install-class filter + Gate C wiring/file symmetry check added to generator)