@thebassclef/lite 1.9.0 → 1.9.2

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.
@@ -0,0 +1,168 @@
1
+ #!/bin/bash
2
+ # tier: upstream
3
+ # fixtures: mock-git-repos-inline
4
+ # Tier 0 test for adopter message channel (bassclef-upstream#1926).
5
+ #
6
+ # Per @luminary alan-cooper Sam+Louis persona + @luminary donald-norman signifier
7
+ # + @luminary linus-torvalds adopter contract.
8
+ #
9
+ # Source under test: .claude/hooks/session-reflection.d/01-adopter-message-channel.sh
10
+ #
11
+ # test-list (per .claude/rules/test-list-discipline.md — RED first, GREEN as they land):
12
+ #
13
+ # Fragment exists + executable
14
+ # [ ] T00: fragment exists at expected path and is executable
15
+ #
16
+ # Fresh install gate — all 3 files absent → banner fires
17
+ # [ ] T01: fresh install (no whereami, no substrate.config, no .claude/settings) → welcome text
18
+ #
19
+ # Onboarded gate — any of the 3 files present → silent
20
+ # [ ] T02: whereami.md present → silent
21
+ # [ ] T03: substrate.config.md present → silent
22
+ # [ ] T04: .claude/settings.json present → silent
23
+ # [ ] T08: bassclef itself (all 3 files present) → silent (Torvalds T1 fold)
24
+ #
25
+ # Override
26
+ # [ ] T05: SKIP_ADOPTER_MESSAGES=1 → silent (bypass on fresh install)
27
+ #
28
+ # Message body (Cooper C2 fold)
29
+ # [ ] T06: welcome text contains "Welcome to bassclef"
30
+ # [ ] T07: welcome text contains "/onboard-repo"
31
+
32
+ set -u
33
+
34
+ REPO_ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"
35
+ HOOK="${REPO_ROOT}/.claude/hooks/session-reflection.d/01-adopter-message-channel.sh"
36
+ PASS=0
37
+ FAIL=0
38
+ FAILED_TESTS=()
39
+
40
+ assert() {
41
+ local name="$1"
42
+ local ok="$2"
43
+ local why="$3"
44
+ if [ "$ok" = "1" ]; then
45
+ PASS=$((PASS + 1))
46
+ echo " PASS: $name"
47
+ else
48
+ FAIL=$((FAIL + 1))
49
+ FAILED_TESTS+=("$name — $why")
50
+ echo " FAIL: $name — $why"
51
+ fi
52
+ }
53
+
54
+ TMPROOT="$(mktemp -d -t adopter-message-channel.XXXXXX)"
55
+ cleanup() { rm -rf "$TMPROOT"; }
56
+ trap cleanup EXIT
57
+
58
+ # --- T00: fragment exists + executable ---
59
+ if [ -x "$HOOK" ]; then
60
+ assert "T00: fragment exists + executable" 1 ""
61
+ else
62
+ assert "T00: fragment exists + executable" 0 "not found or not executable: $HOOK"
63
+ echo ""
64
+ echo "=== Results ==="
65
+ echo "PASS: $PASS"
66
+ echo "FAIL: $FAIL"
67
+ exit 1
68
+ fi
69
+
70
+ # --- Fixture builder ---
71
+ run_hook_in() {
72
+ local tmpdir="$1"
73
+ (cd "$tmpdir" && bash "$HOOK" 2>&1)
74
+ }
75
+
76
+ # --- T01: fresh install (no state files) → welcome text ---
77
+ SC_FRESH="$TMPROOT/fresh"
78
+ mkdir -p "$SC_FRESH"
79
+ OUT_T01=$(run_hook_in "$SC_FRESH")
80
+ if echo "$OUT_T01" | grep -qE "Welcome to bassclef"; then
81
+ assert "T01: fresh install emits welcome text" 1 ""
82
+ else
83
+ assert "T01: fresh install emits welcome text" 0 "no welcome text in: $OUT_T01"
84
+ fi
85
+
86
+ # --- T02: whereami.md present → silent ---
87
+ SC_WHEREAMI="$TMPROOT/whereami-present"
88
+ mkdir -p "$SC_WHEREAMI/docs"
89
+ echo "---" > "$SC_WHEREAMI/docs/whereami.md"
90
+ OUT_T02=$(run_hook_in "$SC_WHEREAMI")
91
+ if [ -z "$OUT_T02" ]; then
92
+ assert "T02: whereami.md present → silent" 1 ""
93
+ else
94
+ assert "T02: whereami.md present → silent" 0 "unexpected output: $OUT_T02"
95
+ fi
96
+
97
+ # --- T03: substrate.config.md present → silent ---
98
+ SC_CONFIG="$TMPROOT/config-present"
99
+ mkdir -p "$SC_CONFIG"
100
+ echo "---" > "$SC_CONFIG/substrate.config.md"
101
+ OUT_T03=$(run_hook_in "$SC_CONFIG")
102
+ if [ -z "$OUT_T03" ]; then
103
+ assert "T03: substrate.config.md present → silent" 1 ""
104
+ else
105
+ assert "T03: substrate.config.md present → silent" 0 "unexpected output: $OUT_T03"
106
+ fi
107
+
108
+ # --- T04: .claude/settings.json present → silent ---
109
+ SC_SETTINGS="$TMPROOT/settings-present"
110
+ mkdir -p "$SC_SETTINGS/.claude"
111
+ echo '{}' > "$SC_SETTINGS/.claude/settings.json"
112
+ OUT_T04=$(run_hook_in "$SC_SETTINGS")
113
+ if [ -z "$OUT_T04" ]; then
114
+ assert "T04: .claude/settings.json present → silent" 1 ""
115
+ else
116
+ assert "T04: .claude/settings.json present → silent" 0 "unexpected output: $OUT_T04"
117
+ fi
118
+
119
+ # --- T05: SKIP_ADOPTER_MESSAGES=1 bypass on fresh install ---
120
+ SC_SKIP="$TMPROOT/skip"
121
+ mkdir -p "$SC_SKIP"
122
+ OUT_T05=$(SKIP_ADOPTER_MESSAGES=1 run_hook_in "$SC_SKIP")
123
+ if [ -z "$OUT_T05" ] || echo "$OUT_T05" | grep -qE "SKIP_ADOPTER_MESSAGES"; then
124
+ assert "T05: SKIP_ADOPTER_MESSAGES=1 bypasses" 1 ""
125
+ else
126
+ assert "T05: SKIP_ADOPTER_MESSAGES=1 bypasses" 0 "banner fired: $OUT_T05"
127
+ fi
128
+
129
+ # --- T06: welcome text contains "Welcome to bassclef" ---
130
+ if echo "$OUT_T01" | grep -qE "Welcome to bassclef"; then
131
+ assert "T06: welcome contains 'Welcome to bassclef'" 1 ""
132
+ else
133
+ assert "T06: welcome contains 'Welcome to bassclef'" 0 "missing in: $OUT_T01"
134
+ fi
135
+
136
+ # --- T07: welcome text contains "/onboard-repo" ---
137
+ if echo "$OUT_T01" | grep -qE "/onboard-repo"; then
138
+ assert "T07: welcome contains '/onboard-repo'" 1 ""
139
+ else
140
+ assert "T07: welcome contains '/onboard-repo'" 0 "missing in: $OUT_T01"
141
+ fi
142
+
143
+ # --- T08: bassclef itself (all 3 files present) → silent ---
144
+ SC_BASSCLEF="$TMPROOT/bassclef"
145
+ mkdir -p "$SC_BASSCLEF/docs" "$SC_BASSCLEF/.claude"
146
+ echo "---" > "$SC_BASSCLEF/docs/whereami.md"
147
+ echo "---" > "$SC_BASSCLEF/substrate.config.md"
148
+ echo '{}' > "$SC_BASSCLEF/.claude/settings.json"
149
+ OUT_T08=$(run_hook_in "$SC_BASSCLEF")
150
+ if [ -z "$OUT_T08" ]; then
151
+ assert "T08: bassclef itself (all 3 present) → silent" 1 ""
152
+ else
153
+ assert "T08: bassclef itself (all 3 present) → silent" 0 "unexpected: $OUT_T08"
154
+ fi
155
+
156
+ # --- Summary ---
157
+ echo ""
158
+ echo "=== Results ==="
159
+ echo "PASS: $PASS"
160
+ echo "FAIL: $FAIL"
161
+ if [ "$FAIL" -gt 0 ]; then
162
+ echo ""
163
+ echo "Failed tests:"
164
+ for t in "${FAILED_TESTS[@]}"; do
165
+ echo " - $t"
166
+ done
167
+ exit 1
168
+ fi
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "v1.4.0",
3
- "marker_tag": "release-2026-09-24-f36b8f31",
4
- "release_date": "2026-09-24T01:12:22Z",
5
- "release_sha": "f36b8f31",
6
- "release_tag": "release-2026-09-24-f36b8f31"
2
+ "version": "v1.5.2",
3
+ "marker_tag": "release-2026-09-24-4dc71e87",
4
+ "release_date": "2026-09-24T21:29:57Z",
5
+ "release_sha": "4dc71e87",
6
+ "release_tag": "release-2026-09-24-4dc71e87"
7
7
  }
@@ -564,25 +564,40 @@ if [ "$FETCH_DONE" = "0" ]; then
564
564
  SYNC_STATUS="freshly cloned"
565
565
  FETCH_DONE=1
566
566
  else
567
- # Banner cure per sunj-labs/bassclef-upstream#1636 — friendly framing paired
568
- # with the bassclef-upstream copy at `.claude/hooks/bassclef-sync.sh` L112-117.
569
- # Bootstrap pair per `.claude/rules/bootstrap-pair-discipline.md`. Diagnostic
570
- # paths list retained (richer than the hook copy because template supports
571
- # strategies A/B/D as well as C).
572
- echo "### Bassclef sync — full-tier not synced"
573
- echo ""
574
- echo "Optional: set up GitHub auth to sync the full bassclef substrate."
575
- echo "Lite tier works without it — your session is fine."
576
- echo "Skills / rules / agents beyond lite become available once sync succeeds."
577
- echo ""
578
- echo "Paths attempted:"
579
- echo " - peer (\$CWD/../bassclef): not present"
580
- if [ "$IS_EPHEMERAL" = "1" ]; then
581
- echo " - HTTP API (.bassclef-source.json): $([ -f "$CWD/.bassclef-source.json" ] && echo "file present but Strategy D fell through (see [bassclef-sync] stderr lines above for reason)" || echo "file missing; run /onboard-repo to write one, or set up .bassclef-url as fallback")"
582
- echo " - S3 (.bassclef-url): $([ -f "$CWD/.bassclef-url" ] && echo "file present but Strategy B fell through" || echo "file missing; run bassclef-s3-publish workflow or merge pending sync PR")"
583
- fi
584
- echo " - bash clone: failed (private repo, no credentials)"
585
- echo ""
567
+ # v1.5.1 refactor (bassclef-upstream#1935 epic + peer bassclef-cli-aa diagnostic on
568
+ # @thebassclef/lite@1.9.0 2026-09-24): the pre-v1.5.1 stdout banner ("### Bassclef sync
569
+ # — full-tier not synced" + Optional-auth prose + Paths attempted list) was fired on
570
+ # every cold-adopter SessionStart. Norman lens (adversarial RFC 2026-09-24): a loud
571
+ # banner on a working state trains adopters to ignore banners.
572
+ #
573
+ # New shape per operator direction 2026-09-24:
574
+ # stdout — one-line RESTORED acknowledgment + JSON contract (peer #1510 harness reads)
575
+ # stderr — [bassclef-sync] diagnostic lines (advanced adopters + operator trace)
576
+ #
577
+ # Cures the #1929 tail defect (postcondition emit unreachable on this branch — see
578
+ # peer's docker-smoke against v1.9.0) in the same edit.
579
+ {
580
+ echo "[bassclef-sync] Strategy A (peer $CWD/../bassclef): not present"
581
+ if [ "$IS_EPHEMERAL" = "1" ]; then
582
+ if [ -f "$CWD/.bassclef-source.json" ]; then
583
+ echo "[bassclef-sync] Strategy D (.bassclef-source.json): config present but fetch fell through (see prior [bassclef-sync] stderr lines)"
584
+ else
585
+ echo "[bassclef-sync] Strategy D (.bassclef-source.json): config missing"
586
+ fi
587
+ if [ -f "$CWD/.bassclef-url" ]; then
588
+ echo "[bassclef-sync] Strategy B (.bassclef-url): URL file present but fetch fell through"
589
+ else
590
+ echo "[bassclef-sync] Strategy B (.bassclef-url): URL file missing"
591
+ fi
592
+ fi
593
+ echo "[bassclef-sync] Strategy C (git clone $BASSCLEF_REPO): failed (no network, no git, or auth required)"
594
+ } >&2
595
+
596
+ _clone_fail_hook_count=$(find "$CWD/.claude/hooks" -maxdepth 1 -name '*.sh' 2>/dev/null | wc -l | tr -d ' ')
597
+ echo "bassclef-sync: RESTORED — lite bundle in place."
598
+ printf 'bassclef-sync: {"status":"complete","installed":%d}\n' "$_clone_fail_hook_count"
599
+ unset _clone_fail_hook_count
600
+
586
601
  exit 0
587
602
  fi
588
603
  fi
@@ -34,6 +34,15 @@ 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
+ ### Track 1 v1.5.1 — bassclef-sync clone-fail postcondition emit + banner-to-stderr (v1.11.0 → v1.11.1, 2026-09-24)
38
+
39
+ - **Change type:** content-change (1 file: `bassclef-sync-template`)
40
+ - **Fields:** 434 entries (unchanged from v1.11.0). Content hash shifts on the `bassclef-sync-template` slug — `presence/install/bassclef-sync.template.sh` gains a postcondition emit block before the L586 clone-fail exit, plus moves the prior multi-line stdout banner to stderr with `[bassclef-sync]` prefix.
41
+ - **Version bump:** v1.11.0 → v1.11.1 (content_hash change only → patch bump per policy).
42
+ - **Rationale:** #1929 tail cure — postcondition emit was unreachable on the clone-fail branch (peer bassclef-cli-aa docker-smoke evidence 2026-09-24 against `@thebassclef/lite@1.9.0`). See PR #1936 + `docs/theses/2026-09-24-bassclef-sync-class-cure-thesis.md` + `docs/rfcs/RFC-2026-09-24-parallel-sync-adversarial.md`.
43
+ - **Downstream cure:** none required. Adopters see one-line `bassclef-sync: RESTORED — lite bundle in place.` on stdout on cold-adopter runs (was multi-line "### Bassclef sync — full-tier not synced" banner). Paths-attempted debug moves to stderr with `[bassclef-sync]` prefix — accessible via `2>&1`. Peer #1510 harness can now grep `RESTORED` on the cold-adopter path to verify cure landing.
44
+ - **Old shape retired:** immediately. The pre-v1.5.1 banner had a factual error (called the public bassclef repo "private" at L584) — no adopters had a stable contract to break.
45
+
37
46
  ### Q1 /longrun Slice D — session-start banner-tone discipline (v1.9.10 → v1.9.11, 2026-09-22)
38
47
 
39
48
  - **Change type:** content-add (1 new standard) + content-change (session-reflection.sh + 3 fragments)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tier": "lite",
3
- "manifest_version": "1.11.0",
4
- "generated_at": "2026-09-24T00:06:17Z",
3
+ "manifest_version": "1.11.1",
4
+ "generated_at": "2026-09-24T21:01:31Z",
5
5
  "entries": [
6
6
  {
7
7
  "slug": "029-release-pipeline",
@@ -1319,7 +1319,7 @@
1319
1319
  "type": "presence-template",
1320
1320
  "path": "presence/install/bassclef-sync.template.sh",
1321
1321
  "tier": "lite",
1322
- "content_hash": "sha256:a122102a034d07ec9a7c4b23e078707160b58aa5409a05eb6e30290fd8c27fb0",
1322
+ "content_hash": "sha256:d79a9a6499c1bcaa368e0472f7a9cd76611f2dbdb8ab2b42533c3f85de2323c4",
1323
1323
  "description": "description: BASSCLEF_SYNC_VERSION=2026-09-06-1496-sessionstart-heal-v1"
1324
1324
  },
1325
1325
  {
@@ -3761,7 +3761,7 @@
3761
3761
  "type": "standard",
3762
3762
  "path": "standards/lite-manifest-schema-changes.md",
3763
3763
  "tier": "lite",
3764
- "content_hash": "sha256:17f5c69efd97240348b6f74d35b200400c2817f7e303eb288b027fbb2bb38991",
3764
+ "content_hash": "sha256:bccea2ce3acc450f35729690e7c24706391c87186ce99ece91e574a8f4686c58",
3765
3765
  "description": "Chronological ledger of every lite-manifest schema change. Adopters read this before sync to know what shifted."
3766
3766
  },
3767
3767
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thebassclef/lite",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "description": "Bassclef CLI — install and upgrade bassclef in your project with two commands.",
5
5
  "keywords": [
6
6
  "bassclef",
@@ -8,7 +8,7 @@
8
8
  "cli",
9
9
  "scaffolding"
10
10
  ],
11
- "homepage": "https://github.com/sunj-labs/bassclef-cli",
11
+ "homepage": "https://docs.bassclef.dev",
12
12
  "repository": {
13
13
  "type": "git",
14
14
  "url": "git+https://github.com/sunj-labs/bassclef-cli.git"