@thebassclef/lite 1.0.1 → 1.0.3
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/dist/cli.cjs +24 -1
- package/dist/cli.js +24 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/hooks/bassclef-sync.sh +98 -16
- package/dist/lite/.claude/hooks/longrun-prep-compounding-sequence-check.sh +3 -3
- package/dist/lite/.claude/hooks/session-reflection.d/00-bassclef-hook-connect.sh +63 -0
- package/dist/lite/.claude/hooks/session-reflection.d/05-active-bet.sh +113 -0
- package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +62 -0
- package/dist/lite/.claude/hooks/session-reflection.d/10-abrupt-stop-recovery.sh +78 -0
- package/dist/lite/.claude/hooks/session-reflection.d/12-session-lock.sh +63 -0
- package/dist/lite/.claude/hooks/session-reflection.d/15-substrate-config-validate.sh +91 -0
- package/dist/lite/.claude/hooks/session-reflection.d/20-artifact-staleness.sh +98 -0
- package/dist/lite/.claude/hooks/session-reflection.d/30-metrics-staleness.sh +61 -0
- package/dist/lite/.claude/hooks/session-reflection.d/35-post-merge-whereami-self-heal.sh +180 -0
- package/dist/lite/.claude/hooks/session-reflection.d/36-whereami-size-check.sh +117 -0
- package/dist/lite/.claude/hooks/session-reflection.d/40-gate-compliance.sh +108 -0
- package/dist/lite/.claude/hooks/session-reflection.d/45-auto-sync-status.sh +99 -0
- package/dist/lite/.claude/hooks/session-reflection.d/50-evolution-issues.sh +44 -0
- package/dist/lite/.claude/hooks/session-reflection.d/55-orientation-gate.sh +187 -0
- package/dist/lite/.claude/hooks/session-reflection.d/56-roadmap-reconcile-gate.sh +88 -0
- package/dist/lite/.claude/hooks/session-reflection.d/60-deferred-actions.sh +212 -0
- package/dist/lite/.claude/hooks/session-reflection.d/70-recent-strategic-artifacts.sh +101 -0
- package/dist/lite/.claude/hooks/session-reflection.d/75-prior-r8-findings.sh +100 -0
- package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +87 -0
- package/dist/lite/.claude/hooks/session-reflection.d/80-workflow-staleness.sh +141 -0
- package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +67 -0
- package/dist/lite/.claude/hooks/session-reflection.d/90-release-backlog.sh +140 -0
- package/dist/lite/.claude/hooks/session-reflection.d/90-secrets-expiry.sh +104 -0
- package/dist/lite/.claude/hooks/session-reflection.d/95-settings-hook-verify.sh +131 -0
- package/dist/lite/.claude/hooks/session-reflection.d/95-telemetry-emit.sh +66 -0
- package/dist/lite/.claude/hooks/session-reflection.d/97-install-class-dispatch.sh +57 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/00-bassclef-hook-connect.test.sh +492 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/05-active-bet.test.sh +336 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/12-session-lock.test.sh +216 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/15-substrate-config-validate.test.sh +50 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/20-artifact-staleness.test.sh +348 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/36-whereami-size-check.test.sh +189 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/45-auto-sync-status.test.sh +263 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/55-orientation-gate.test.sh +595 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/56-roadmap-reconcile-gate.test.sh +227 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/75-prior-r8-findings.test.sh +142 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/90-release-backlog.test.sh +44 -0
- package/dist/lite/.claude/hooks/trace-helper.sh +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: standard
|
|
3
|
+
# Tests for .claude/hooks/session-reflection.d/56-roadmap-reconcile-gate.sh
|
|
4
|
+
#
|
|
5
|
+
# Per bassclef#1183 + bassclef#504: mechanical enforcement at SessionStart
|
|
6
|
+
# in bassclef repo. Fires BLOCKED on feature branches without a
|
|
7
|
+
# roadmap-reconcile marker, so /sprint + /longrun prep procedures
|
|
8
|
+
# (WU-3/WU-4) refuse to propose work until /roadmap-reconcile --dry-run
|
|
9
|
+
# has run (and either showed no drift OR drift was resolved or deferred).
|
|
10
|
+
#
|
|
11
|
+
# Tier 0 strict-TDD per bassclef#1037; test list block + sufficiency
|
|
12
|
+
# criteria per bassclef#1090 + bassclef#1098.
|
|
13
|
+
#
|
|
14
|
+
# Run: bash .claude/hooks/session-reflection.d/tests/56-roadmap-reconcile-gate.test.sh
|
|
15
|
+
|
|
16
|
+
set -u
|
|
17
|
+
|
|
18
|
+
# test-list:
|
|
19
|
+
# [x]Branch: fires BLOCKED in consumer repo too (bassclef#1275 — drop bassclef-only guard)
|
|
20
|
+
# [x]Branch: silent when in bassclef repo AND marker exists for current branch
|
|
21
|
+
# [x]Branch: fires BLOCKED when in bassclef repo AND no marker for current branch
|
|
22
|
+
# [x]Branch: silent on main (no marker required for trunk)
|
|
23
|
+
# [x]Exit: exit 0 on all paths (SessionStart hooks emit informational BLOCKED)
|
|
24
|
+
# [x]Exit: exit 0 when override SKIP_ROADMAP_RECONCILE_GATE=1 is set
|
|
25
|
+
# [x]Exit: exit 0 on missing binaries (graceful)
|
|
26
|
+
# [x]BLOCKED content: emits "🛑 BLOCKED: roadmap-reconcile-gate" header
|
|
27
|
+
# [x]BLOCKED content: includes the /roadmap-reconcile --dry-run dispatch command
|
|
28
|
+
# [x]BLOCKED content: includes resolution path naming the marker file pattern
|
|
29
|
+
# [x]BLOCKED content: includes override path (SKIP_ROADMAP_RECONCILE_GATE=1)
|
|
30
|
+
# [x]BLOCKED content: cites bassclef#1183 + bassclef#504
|
|
31
|
+
# [x]Override: SKIP_ROADMAP_RECONCILE_GATE=1 silences output entirely
|
|
32
|
+
# [x]Marker: marker at state/markers/roadmap-reconcile-gate/<branch-slug>.marker silences hook
|
|
33
|
+
# [x]Marker: marker on a DIFFERENT branch does NOT silence
|
|
34
|
+
# [x]Marker: handles branch slug with slash (feature/foo → feature-foo)
|
|
35
|
+
# [x]External-binary: silent when gh binary missing (no crash)
|
|
36
|
+
# [~] State-file: no specific state files read; this gate is marker-only. Reason: hook only checks marker existence.
|
|
37
|
+
# [~] Trap: no tmpfiles created in hook; no trap needed. Reason: read-only on filesystem except marker check.
|
|
38
|
+
|
|
39
|
+
REPO_ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"
|
|
40
|
+
HOOK="${REPO_ROOT}/.claude/hooks/session-reflection.d/56-roadmap-reconcile-gate.sh"
|
|
41
|
+
PASS=0
|
|
42
|
+
FAIL=0
|
|
43
|
+
FAILED_TESTS=()
|
|
44
|
+
|
|
45
|
+
assert() {
|
|
46
|
+
local name="$1"
|
|
47
|
+
local result="$2"
|
|
48
|
+
if [ "$result" = "ok" ]; then
|
|
49
|
+
PASS=$((PASS + 1))
|
|
50
|
+
echo " PASS $name"
|
|
51
|
+
else
|
|
52
|
+
FAIL=$((FAIL + 1))
|
|
53
|
+
FAILED_TESTS+=("$name")
|
|
54
|
+
echo " FAIL $name — $result"
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setup_tmpdir() {
|
|
59
|
+
TMPDIR_TEST="$(mktemp -d)"
|
|
60
|
+
mkdir -p "$TMPDIR_TEST/.claude/hooks" "$TMPDIR_TEST/state/markers/roadmap-reconcile-gate"
|
|
61
|
+
(cd "$TMPDIR_TEST" && git init -q && git config user.email t@t && git config user.name t \
|
|
62
|
+
&& git checkout -q -b feature/test-branch 2>/dev/null \
|
|
63
|
+
&& touch README.md && git add README.md && git commit -q -m init 2>/dev/null) || true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
teardown_tmpdir() {
|
|
67
|
+
rm -rf "$TMPDIR_TEST"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
stub_gh_bassclef() {
|
|
71
|
+
cat > "$TMPDIR_TEST/gh" <<'EOF'
|
|
72
|
+
#!/usr/bin/env bash
|
|
73
|
+
if [ "$1" = "repo" ] && [ "$2" = "view" ]; then
|
|
74
|
+
echo "${GH_STUB_REPO_NAME:-bassclef}"
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
exit 0
|
|
78
|
+
EOF
|
|
79
|
+
chmod +x "$TMPDIR_TEST/gh"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
run_hook() {
|
|
83
|
+
HOOK_STDOUT=$(cd "$TMPDIR_TEST" \
|
|
84
|
+
&& PATH="$TMPDIR_TEST:$PATH" \
|
|
85
|
+
&& CLAUDE_PROJECT_DIR="$TMPDIR_TEST" \
|
|
86
|
+
bash "$HOOK" 2>&1)
|
|
87
|
+
HOOK_EXIT=$?
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if [ ! -x "$HOOK" ]; then
|
|
91
|
+
chmod +x "$HOOK" 2>/dev/null || true
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo "Testing $HOOK"
|
|
95
|
+
echo "---"
|
|
96
|
+
|
|
97
|
+
# Fires BLOCKED in consumer repo too — adopter inherits the discipline (bassclef#1275)
|
|
98
|
+
setup_tmpdir
|
|
99
|
+
stub_gh_bassclef
|
|
100
|
+
GH_STUB_REPO_NAME=poa run_hook
|
|
101
|
+
[ "$HOOK_EXIT" = "0" ] && echo "$HOOK_STDOUT" | grep -q "roadmap-reconcile-gate" && \
|
|
102
|
+
assert "fires BLOCKED in consumer repo too (bassclef#1275)" "ok" || \
|
|
103
|
+
assert "fires BLOCKED in consumer repo too (bassclef#1275)" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
104
|
+
teardown_tmpdir
|
|
105
|
+
|
|
106
|
+
# Fires BLOCKED in bassclef + no marker
|
|
107
|
+
setup_tmpdir
|
|
108
|
+
stub_gh_bassclef
|
|
109
|
+
run_hook
|
|
110
|
+
[ "$HOOK_EXIT" = "0" ] && echo "$HOOK_STDOUT" | grep -q "roadmap-reconcile-gate" && \
|
|
111
|
+
assert "fires BLOCKED in bassclef with no marker" "ok" || \
|
|
112
|
+
assert "fires BLOCKED in bassclef with no marker" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
113
|
+
teardown_tmpdir
|
|
114
|
+
|
|
115
|
+
# Silent on main
|
|
116
|
+
setup_tmpdir
|
|
117
|
+
stub_gh_bassclef
|
|
118
|
+
(cd "$TMPDIR_TEST" && git checkout -q -b main 2>/dev/null || git checkout -q main 2>/dev/null)
|
|
119
|
+
run_hook
|
|
120
|
+
[ "$HOOK_EXIT" = "0" ] && [ -z "$HOOK_STDOUT" ] && \
|
|
121
|
+
assert "silent on main branch" "ok" || \
|
|
122
|
+
assert "silent on main branch" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
123
|
+
teardown_tmpdir
|
|
124
|
+
|
|
125
|
+
# BLOCKED content checks
|
|
126
|
+
setup_tmpdir
|
|
127
|
+
stub_gh_bassclef
|
|
128
|
+
run_hook
|
|
129
|
+
echo "$HOOK_STDOUT" | grep -q "🛑 BLOCKED: roadmap-reconcile-gate" && \
|
|
130
|
+
assert "BLOCKED header emitted" "ok" || \
|
|
131
|
+
assert "BLOCKED header emitted" "output=$HOOK_STDOUT"
|
|
132
|
+
teardown_tmpdir
|
|
133
|
+
|
|
134
|
+
setup_tmpdir
|
|
135
|
+
stub_gh_bassclef
|
|
136
|
+
run_hook
|
|
137
|
+
echo "$HOOK_STDOUT" | grep -q "roadmap-reconcile --dry-run" && \
|
|
138
|
+
assert "dispatch command surfaced in BLOCKED" "ok" || \
|
|
139
|
+
assert "dispatch command surfaced in BLOCKED" "output=$HOOK_STDOUT"
|
|
140
|
+
teardown_tmpdir
|
|
141
|
+
|
|
142
|
+
setup_tmpdir
|
|
143
|
+
stub_gh_bassclef
|
|
144
|
+
run_hook
|
|
145
|
+
echo "$HOOK_STDOUT" | grep -qE "state/markers/roadmap-reconcile-gate" && \
|
|
146
|
+
assert "resolution path names marker file pattern" "ok" || \
|
|
147
|
+
assert "resolution path names marker file pattern" "output=$HOOK_STDOUT"
|
|
148
|
+
teardown_tmpdir
|
|
149
|
+
|
|
150
|
+
setup_tmpdir
|
|
151
|
+
stub_gh_bassclef
|
|
152
|
+
run_hook
|
|
153
|
+
echo "$HOOK_STDOUT" | grep -q "SKIP_ROADMAP_RECONCILE_GATE=1" && \
|
|
154
|
+
assert "override path documented in BLOCKED" "ok" || \
|
|
155
|
+
assert "override path documented in BLOCKED" "output=$HOOK_STDOUT"
|
|
156
|
+
teardown_tmpdir
|
|
157
|
+
|
|
158
|
+
setup_tmpdir
|
|
159
|
+
stub_gh_bassclef
|
|
160
|
+
run_hook
|
|
161
|
+
echo "$HOOK_STDOUT" | grep -q "bassclef#1183" && echo "$HOOK_STDOUT" | grep -q "bassclef#504" && \
|
|
162
|
+
assert "BLOCKED cites bassclef#1183 + bassclef#504" "ok" || \
|
|
163
|
+
assert "BLOCKED cites bassclef#1183 + bassclef#504" "output=$HOOK_STDOUT"
|
|
164
|
+
teardown_tmpdir
|
|
165
|
+
|
|
166
|
+
# Override silences
|
|
167
|
+
setup_tmpdir
|
|
168
|
+
stub_gh_bassclef
|
|
169
|
+
HOOK_STDOUT=$(cd "$TMPDIR_TEST" && PATH="$TMPDIR_TEST:$PATH" CLAUDE_PROJECT_DIR="$TMPDIR_TEST" SKIP_ROADMAP_RECONCILE_GATE=1 bash "$HOOK" 2>&1)
|
|
170
|
+
HOOK_EXIT=$?
|
|
171
|
+
[ "$HOOK_EXIT" = "0" ] && [ -z "$HOOK_STDOUT" ] && \
|
|
172
|
+
assert "SKIP_ROADMAP_RECONCILE_GATE=1 silences hook" "ok" || \
|
|
173
|
+
assert "SKIP_ROADMAP_RECONCILE_GATE=1 silences hook" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
174
|
+
teardown_tmpdir
|
|
175
|
+
|
|
176
|
+
# Marker for current branch silences
|
|
177
|
+
setup_tmpdir
|
|
178
|
+
stub_gh_bassclef
|
|
179
|
+
touch "$TMPDIR_TEST/state/markers/roadmap-reconcile-gate/feature-test-branch.marker"
|
|
180
|
+
run_hook
|
|
181
|
+
[ "$HOOK_EXIT" = "0" ] && [ -z "$HOOK_STDOUT" ] && \
|
|
182
|
+
assert "marker for current branch silences hook" "ok" || \
|
|
183
|
+
assert "marker for current branch silences hook" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
184
|
+
teardown_tmpdir
|
|
185
|
+
|
|
186
|
+
# Marker on other branch does NOT silence
|
|
187
|
+
setup_tmpdir
|
|
188
|
+
stub_gh_bassclef
|
|
189
|
+
touch "$TMPDIR_TEST/state/markers/roadmap-reconcile-gate/feature-OTHER-branch.marker"
|
|
190
|
+
run_hook
|
|
191
|
+
[ "$HOOK_EXIT" = "0" ] && echo "$HOOK_STDOUT" | grep -q "roadmap-reconcile-gate" && \
|
|
192
|
+
assert "marker on other branch does NOT silence" "ok" || \
|
|
193
|
+
assert "marker on other branch does NOT silence" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
194
|
+
teardown_tmpdir
|
|
195
|
+
|
|
196
|
+
# Slash-in-branch-name
|
|
197
|
+
setup_tmpdir
|
|
198
|
+
stub_gh_bassclef
|
|
199
|
+
touch "$TMPDIR_TEST/state/markers/roadmap-reconcile-gate/feature-test-branch.marker"
|
|
200
|
+
run_hook
|
|
201
|
+
[ "$HOOK_EXIT" = "0" ] && [ -z "$HOOK_STDOUT" ] && \
|
|
202
|
+
assert "slash-in-branch-name handled (feature/foo → feature-foo)" "ok" || \
|
|
203
|
+
assert "slash-in-branch-name handled (feature/foo → feature-foo)" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
204
|
+
teardown_tmpdir
|
|
205
|
+
|
|
206
|
+
# Missing gh binary graceful
|
|
207
|
+
setup_tmpdir
|
|
208
|
+
HOOK_STDOUT=$(cd "$TMPDIR_TEST" && PATH="/usr/bin:/bin" CLAUDE_PROJECT_DIR="$TMPDIR_TEST" bash "$HOOK" 2>&1)
|
|
209
|
+
HOOK_EXIT=$?
|
|
210
|
+
[ "$HOOK_EXIT" = "0" ] && \
|
|
211
|
+
assert "missing gh binary does not crash" "ok" || \
|
|
212
|
+
assert "missing gh binary does not crash" "exit=$HOOK_EXIT output=$HOOK_STDOUT"
|
|
213
|
+
teardown_tmpdir
|
|
214
|
+
|
|
215
|
+
echo "---"
|
|
216
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
217
|
+
|
|
218
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
219
|
+
echo ""
|
|
220
|
+
echo "Failed tests:"
|
|
221
|
+
for t in "${FAILED_TESTS[@]}"; do
|
|
222
|
+
echo " - $t"
|
|
223
|
+
done
|
|
224
|
+
exit 1
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
exit 0
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: standard
|
|
3
|
+
# fixtures: bassclef-upstream-self
|
|
4
|
+
# Tier 0 strict TDD for 75-prior-r8-findings.sh (bet 2026-07-03a WU-4)
|
|
5
|
+
#
|
|
6
|
+
# test-list:
|
|
7
|
+
# [x] SKIP_PRIOR_R8_FINDINGS=1 override silent
|
|
8
|
+
# [x] No chronicle dir silent
|
|
9
|
+
# [x] Empty chronicle dir silent
|
|
10
|
+
# [x] Chronicles without R8 mentions silent
|
|
11
|
+
# [x] Chronicle with R8 mention emits summary
|
|
12
|
+
# [x] Multiple chronicles with R8 mentions aggregate
|
|
13
|
+
# [x] Exit 0 always
|
|
14
|
+
# [x] Names the file that matched
|
|
15
|
+
|
|
16
|
+
set +e
|
|
17
|
+
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
HOOK="$SCRIPT_DIR/../75-prior-r8-findings.sh"
|
|
20
|
+
|
|
21
|
+
PASS=0
|
|
22
|
+
FAIL=0
|
|
23
|
+
pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
|
|
24
|
+
fail() { echo "FAIL: $1"; echo " $2"; FAIL=$((FAIL + 1)); }
|
|
25
|
+
|
|
26
|
+
# Setup — temp dir with fake chronicle/ inside
|
|
27
|
+
setup_workspace() {
|
|
28
|
+
TMPDIR_TEST=$(mktemp -d)
|
|
29
|
+
mkdir -p "$TMPDIR_TEST/chronicle"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
teardown_workspace() {
|
|
33
|
+
rm -rf "$TMPDIR_TEST"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# === Test 1 — SKIP override ===
|
|
37
|
+
setup_workspace
|
|
38
|
+
echo "R8 finding here." > "$TMPDIR_TEST/chronicle/2026-07-01-test.md"
|
|
39
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && SKIP_PRIOR_R8_FINDINGS=1 bash "$HOOK" 2>&1)
|
|
40
|
+
STATUS=$?
|
|
41
|
+
teardown_workspace
|
|
42
|
+
if [ $STATUS -eq 0 ] && [ -z "$OUTPUT" ]; then
|
|
43
|
+
pass "SKIP override silent"
|
|
44
|
+
else
|
|
45
|
+
fail "SKIP override" "status=$STATUS output=$OUTPUT"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# === Test 2 — No chronicle dir ===
|
|
49
|
+
TMPDIR_TEST=$(mktemp -d)
|
|
50
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
51
|
+
STATUS=$?
|
|
52
|
+
rm -rf "$TMPDIR_TEST"
|
|
53
|
+
if [ $STATUS -eq 0 ] && [ -z "$OUTPUT" ]; then
|
|
54
|
+
pass "No chronicle dir silent"
|
|
55
|
+
else
|
|
56
|
+
fail "No chronicle dir" "status=$STATUS output=$OUTPUT"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# === Test 3 — Empty chronicle dir ===
|
|
60
|
+
setup_workspace
|
|
61
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
62
|
+
STATUS=$?
|
|
63
|
+
teardown_workspace
|
|
64
|
+
if [ $STATUS -eq 0 ] && [ -z "$OUTPUT" ]; then
|
|
65
|
+
pass "Empty chronicle silent"
|
|
66
|
+
else
|
|
67
|
+
fail "Empty chronicle" "status=$STATUS output=$OUTPUT"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# === Test 4 — Chronicles without R8 mentions ===
|
|
71
|
+
setup_workspace
|
|
72
|
+
echo "Nothing special here. Just prose." > "$TMPDIR_TEST/chronicle/2026-07-01-nofind.md"
|
|
73
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
74
|
+
STATUS=$?
|
|
75
|
+
teardown_workspace
|
|
76
|
+
if [ $STATUS -eq 0 ] && [ -z "$OUTPUT" ]; then
|
|
77
|
+
pass "No R8 mentions silent"
|
|
78
|
+
else
|
|
79
|
+
fail "No R8 mentions" "status=$STATUS output=$OUTPUT"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# === Test 5 — Chronicle with R8 mention emits summary ===
|
|
83
|
+
setup_workspace
|
|
84
|
+
cat > "$TMPDIR_TEST/chronicle/2026-07-01-r8find.md" <<'EOM'
|
|
85
|
+
This session caught an R8 pattern.
|
|
86
|
+
The agent asserted without validation.
|
|
87
|
+
Claim-shape prose without cited sources.
|
|
88
|
+
EOM
|
|
89
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
90
|
+
STATUS=$?
|
|
91
|
+
teardown_workspace
|
|
92
|
+
if [ $STATUS -eq 0 ] && echo "$OUTPUT" | grep -q "PRIOR R8 FINDINGS"; then
|
|
93
|
+
pass "R8 mention emits summary"
|
|
94
|
+
else
|
|
95
|
+
fail "R8 mention summary" "status=$STATUS output=$OUTPUT"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# === Test 6 — Multiple chronicles aggregate ===
|
|
99
|
+
setup_workspace
|
|
100
|
+
echo "R8 finding one" > "$TMPDIR_TEST/chronicle/2026-07-01a.md"
|
|
101
|
+
echo "R8 finding two" > "$TMPDIR_TEST/chronicle/2026-07-02b.md"
|
|
102
|
+
echo "R8 finding three" > "$TMPDIR_TEST/chronicle/2026-07-03c.md"
|
|
103
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
104
|
+
STATUS=$?
|
|
105
|
+
teardown_workspace
|
|
106
|
+
COUNT=$(echo "$OUTPUT" | grep -c "R8-related mentions")
|
|
107
|
+
if [ $STATUS -eq 0 ] && [ "$COUNT" -ge 2 ]; then
|
|
108
|
+
pass "Multiple chronicles aggregate"
|
|
109
|
+
else
|
|
110
|
+
fail "Multiple aggregate" "status=$STATUS count=$COUNT output=$OUTPUT"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# === Test 7 — Exit 0 always (even with parse issues) ===
|
|
114
|
+
setup_workspace
|
|
115
|
+
# Put a binary file to test robustness
|
|
116
|
+
head -c 100 /dev/urandom > "$TMPDIR_TEST/chronicle/2026-07-01-binary.md"
|
|
117
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
118
|
+
STATUS=$?
|
|
119
|
+
teardown_workspace
|
|
120
|
+
if [ $STATUS -eq 0 ]; then
|
|
121
|
+
pass "Exit 0 even with binary"
|
|
122
|
+
else
|
|
123
|
+
fail "Exit 0 with binary" "status=$STATUS"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# === Test 8 — Names the file that matched ===
|
|
127
|
+
setup_workspace
|
|
128
|
+
echo "assertion-shape catch here" > "$TMPDIR_TEST/chronicle/2026-07-03-named.md"
|
|
129
|
+
OUTPUT=$(cd "$TMPDIR_TEST" && bash "$HOOK" 2>&1)
|
|
130
|
+
STATUS=$?
|
|
131
|
+
teardown_workspace
|
|
132
|
+
if [ $STATUS -eq 0 ] && echo "$OUTPUT" | grep -q "2026-07-03-named.md"; then
|
|
133
|
+
pass "Names matched file"
|
|
134
|
+
else
|
|
135
|
+
fail "Names matched file" "status=$STATUS output=$OUTPUT"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
echo ""
|
|
139
|
+
echo "==========================================="
|
|
140
|
+
echo " PASS: $PASS FAIL: $FAIL"
|
|
141
|
+
echo "==========================================="
|
|
142
|
+
[ $FAIL -eq 0 ]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: standard
|
|
3
|
+
# Minimal Tier 1 sibling test for 90-release-backlog.sh.
|
|
4
|
+
# Coordinator-level integration coverage lives at:
|
|
5
|
+
# .claude/hooks/tests/session-reflection-coordinator.test.sh
|
|
6
|
+
|
|
7
|
+
set -u
|
|
8
|
+
|
|
9
|
+
REPO_ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"
|
|
10
|
+
MODULE="${REPO_ROOT}/.claude/hooks/session-reflection.d/90-release-backlog.sh"
|
|
11
|
+
|
|
12
|
+
PASS=0
|
|
13
|
+
FAIL=0
|
|
14
|
+
|
|
15
|
+
assert() {
|
|
16
|
+
if [ "$2" = "ok" ]; then PASS=$((PASS+1)); echo " PASS $1"; else FAIL=$((FAIL+1)); echo " FAIL $1 — $2"; fi
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
echo "Testing $MODULE (minimal stub — full coverage via coordinator test)"
|
|
20
|
+
|
|
21
|
+
if [ -f "$MODULE" ]; then
|
|
22
|
+
assert "module file present" "ok"
|
|
23
|
+
else
|
|
24
|
+
assert "module file present" "not found at $MODULE"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if bash -n "$MODULE" 2>/dev/null; then
|
|
28
|
+
assert "syntax valid" "ok"
|
|
29
|
+
else
|
|
30
|
+
assert "syntax valid" "bash -n reported syntax error"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Cure b (2026-07-30) converted inline `... || exit 0` patterns to the
|
|
34
|
+
# dual pattern so the coordinator survives when this module short-circuits.
|
|
35
|
+
if grep -q "return 0 2>/dev/null || exit 0" "$MODULE"; then
|
|
36
|
+
assert "cure b dual pattern present" "ok"
|
|
37
|
+
else
|
|
38
|
+
assert "cure b dual pattern present" "expected 'return 0 2>/dev/null || exit 0' in module"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
echo ""
|
|
42
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
43
|
+
[ "$FAIL" -gt 0 ] && exit 1
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# SDLC Trace Log helper — sourced by all hooks.
|
|
4
|
+
# Appends a trigger line to docs/sdlc-traces/YYYY-MM-DD.log
|
|
5
|
+
#
|
|
6
|
+
# Usage: source this file, then call:
|
|
7
|
+
# trace_log "hook-name" "trigger-description"
|
|
8
|
+
|
|
9
|
+
TRACE_DIR="docs/sdlc-traces"
|
|
10
|
+
|
|
11
|
+
trace_log() {
|
|
12
|
+
local hook="$1"
|
|
13
|
+
local trigger="$2"
|
|
14
|
+
local timestamp
|
|
15
|
+
timestamp=$(date +%H:%M:%S)
|
|
16
|
+
local today
|
|
17
|
+
today=$(date +%Y-%m-%d)
|
|
18
|
+
local log_file="${TRACE_DIR}/${today}.log"
|
|
19
|
+
|
|
20
|
+
mkdir -p "$TRACE_DIR" 2>/dev/null || true
|
|
21
|
+
echo "${timestamp} | ${hook} | ${trigger} | — | —" >> "$log_file" 2>/dev/null || true
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thebassclef/lite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Bassclef CLI — install and upgrade bassclef in your project with two commands.",
|
|
5
5
|
"keywords": ["bassclef", "claude-code", "cli", "scaffolding"],
|
|
6
6
|
"homepage": "https://github.com/sunj-labs/bassclef-cli",
|