@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.
- package/README.md +1 -1
- package/dist/cli.cjs +237 -3
- package/dist/cli.js +238 -4
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/bassclef-orientation.md +27 -0
- package/dist/lite/.claude/hooks/session-reflection.d/70-recent-strategic-artifacts.sh +4 -2
- package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +4 -2
- package/dist/lite/.claude/hooks/session-reflection.d/80-workflow-staleness.sh +3 -1
- package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +21 -0
- package/dist/lite/.claude/hooks/session-reflection.d/95-settings-hook-verify.sh +14 -11
- package/dist/lite/.claude/hooks/session-reflection.sh +23 -14
- package/dist/lite/.claude/rules/longrun-prep-plan-doc-compression.md +25 -6
- package/dist/lite/.claude/settings.json +5 -1
- package/dist/lite/.claude/skills/longrun/SKILL.md +23 -6
- package/dist/lite/bassclef-version.json +7 -0
- package/dist/lite/gitignore +8 -0
- package/dist/lite/lib/mechanism-fidelity.sh +34 -4
- package/dist/lite/lib/source-graph-walker.sh +29 -2
- package/dist/lite/presence/cli/bassclef-statusline.dispatcher.sh +78 -0
- package/dist/lite/presence/cli/bassclef-statusline.sh +78 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +41 -0
- package/dist/lite/standards/lite-manifest.json +22 -14
- package/dist/lite/standards/session-start-banner-discipline.md +99 -0
- package/package.json +3 -2
|
@@ -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
|
-
|
|
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
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
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** |
|
|
29
|
-
| **exploratory** | No
|
|
30
|
-
| **reversible-small** | Small scope stated in the invocation +
|
|
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
|
-
-
|
|
76
|
-
-
|
|
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** |
|
|
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 +
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
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.
|
package/dist/lite/gitignore
CHANGED
|
@@ -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
|
|
560
|
-
#
|
|
561
|
-
#
|
|
562
|
-
#
|
|
582
|
+
# Layer 2 + bassclef-upstream#1880 — read 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)
|