@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,104 @@
|
|
|
1
|
+
# tier: lite
|
|
2
|
+
# Secrets-expiry scan: parse substrate.secrets.md, surface BLOCKED
|
|
3
|
+
# at session start when any secret is within alert_threshold_days.
|
|
4
|
+
#
|
|
5
|
+
# Schema: standards/state-spine/schemas/substrate-secrets.schema.json
|
|
6
|
+
# Standard: standards/secrets-lifecycle.md
|
|
7
|
+
# Rule: (paired with .claude/rules/substrate-config-schema.md cross-reference)
|
|
8
|
+
# Refs: bassclef#381
|
|
9
|
+
#
|
|
10
|
+
# Behavior:
|
|
11
|
+
# - Silent when no substrate.secrets.md (graceful in repos without secrets)
|
|
12
|
+
# - Silent when all secrets in OK state
|
|
13
|
+
# - Surfaces BLOCKED block listing every WARN / ALERT / EXPIRED secret
|
|
14
|
+
# with rotation procedure path
|
|
15
|
+
# - Override per-session: SKIP_SECRETS_EXPIRY_CHECK=1 (logged to stderr)
|
|
16
|
+
|
|
17
|
+
# Per-session override
|
|
18
|
+
if [ "${SKIP_SECRETS_EXPIRY_CHECK:-0}" = "1" ]; then
|
|
19
|
+
echo "[secrets-expiry: SKIP_SECRETS_EXPIRY_CHECK=1, skipping]" >&2
|
|
20
|
+
return 0 2>/dev/null || true
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
SECRETS_FILE="${CWD:-$(pwd)}/substrate.secrets.md"
|
|
24
|
+
|
|
25
|
+
# No file → graceful exit (consumer repo without secrets is fine)
|
|
26
|
+
if [ ! -f "$SECRETS_FILE" ]; then
|
|
27
|
+
return 0 2>/dev/null || true
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Locate the status script. Prefer consumer-repo path; fall back to
|
|
31
|
+
# bassclef-vendored path if available.
|
|
32
|
+
STATUS_SCRIPT="${CWD:-$(pwd)}/scripts/secrets-status.sh"
|
|
33
|
+
if [ ! -x "$STATUS_SCRIPT" ] && [ -n "${BASSCLEF_DIR:-}" ]; then
|
|
34
|
+
STATUS_SCRIPT="${BASSCLEF_DIR}/scripts/secrets-status.sh"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [ ! -x "$STATUS_SCRIPT" ]; then
|
|
38
|
+
# Script missing — surface as BLOCKED with installation hint.
|
|
39
|
+
blocked_banner "secrets-expiry — scripts/secrets-status.sh not found
|
|
40
|
+
|
|
41
|
+
substrate.secrets.md exists at $SECRETS_FILE but the status script is
|
|
42
|
+
missing. The hook can't check expiry without it.
|
|
43
|
+
|
|
44
|
+
Resolution:
|
|
45
|
+
- If this is bassclef: ensure scripts/secrets-status.sh is committed
|
|
46
|
+
- If this is a consumer repo: re-run /onboard-repo to vendor the script
|
|
47
|
+
|
|
48
|
+
Override: SKIP_SECRETS_EXPIRY_CHECK=1 <command>
|
|
49
|
+
Standard: standards/secrets-lifecycle.md"
|
|
50
|
+
return 0 2>/dev/null || true
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Run status script in JSON mode for parseable output
|
|
54
|
+
STATUS_JSON="$(SECRETS_FILE="$SECRETS_FILE" bash "$STATUS_SCRIPT" --json 2>/dev/null || echo '')"
|
|
55
|
+
|
|
56
|
+
if [ -z "$STATUS_JSON" ]; then
|
|
57
|
+
return 0 2>/dev/null || true
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Extract WARN / ALERT / EXPIRED entries via python3 (jq optional).
|
|
61
|
+
# Each line of output is "STATE|NAME|EXPIRES|DAYS|PROCEDURE"
|
|
62
|
+
PROBLEM_ENTRIES="$(echo "$STATUS_JSON" | python3 -c "
|
|
63
|
+
import sys, json
|
|
64
|
+
try:
|
|
65
|
+
d = json.load(sys.stdin)
|
|
66
|
+
except Exception:
|
|
67
|
+
sys.exit(0)
|
|
68
|
+
for s in d.get('secrets', []):
|
|
69
|
+
state = s.get('state', '')
|
|
70
|
+
if state in ('WARN', 'ALERT', 'EXPIRED'):
|
|
71
|
+
print(f\"{state}|{s.get('name','')}|{s.get('expires_at','')}|{s.get('days_remaining','')}|{s.get('rotation_procedure','')}\")
|
|
72
|
+
" 2>/dev/null || echo '')"
|
|
73
|
+
|
|
74
|
+
if [ -z "$PROBLEM_ENTRIES" ]; then
|
|
75
|
+
return 0 2>/dev/null || true
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Build BLOCKED banner content
|
|
79
|
+
MSG="secrets-expiry — at least one credential within alert window
|
|
80
|
+
|
|
81
|
+
"
|
|
82
|
+
|
|
83
|
+
while IFS='|' read -r state name expires days proc; do
|
|
84
|
+
case "$state" in
|
|
85
|
+
EXPIRED) glyph="💀 EXPIRED" ;;
|
|
86
|
+
ALERT) glyph="🛑 ALERT " ;;
|
|
87
|
+
WARN) glyph="⚠️ WARN " ;;
|
|
88
|
+
*) glyph="$state" ;;
|
|
89
|
+
esac
|
|
90
|
+
MSG="$MSG $glyph $name expires $expires ($days days)
|
|
91
|
+
rotate: $proc
|
|
92
|
+
"
|
|
93
|
+
done <<< "$PROBLEM_ENTRIES"
|
|
94
|
+
|
|
95
|
+
MSG="$MSG
|
|
96
|
+
Resolution paths:
|
|
97
|
+
1. Rotate the credential per its rotation_procedure runbook
|
|
98
|
+
2. Update substrate.secrets.md (last_rotated + expires_at) after rotation
|
|
99
|
+
3. Verify with: bash scripts/secrets-status.sh
|
|
100
|
+
|
|
101
|
+
Override (per-session): SKIP_SECRETS_EXPIRY_CHECK=1 <command>
|
|
102
|
+
Standard: standards/secrets-lifecycle.md"
|
|
103
|
+
|
|
104
|
+
blocked_banner "$MSG"
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# tier: lite
|
|
2
|
+
# Settings hook path verifier — fires at every SessionStart via
|
|
3
|
+
# session-reflection.sh. Reads project settings.json (and user
|
|
4
|
+
# settings.json when reachable), enumerates every hook command path,
|
|
5
|
+
# checks each file exists on disk. Fires BLOCKED banner when any wired
|
|
6
|
+
# hook path resolves to a missing file.
|
|
7
|
+
#
|
|
8
|
+
# Closes the silent staleness class per bassclef-upstream#888. When a
|
|
9
|
+
# hook path in settings.json points at a file that got renamed, deleted,
|
|
10
|
+
# or never installed, SessionStart today prints a non-blocking error and
|
|
11
|
+
# the session continues. Adopters miss the signal. Substrate discipline
|
|
12
|
+
# quietly disappears from that session's context.
|
|
13
|
+
#
|
|
14
|
+
# Sourced (not exec'd) by session-reflection.sh. Inherits:
|
|
15
|
+
# - blocked_banner() function
|
|
16
|
+
# - trace_log() function
|
|
17
|
+
# - BASSCLEF_DIR environment variable
|
|
18
|
+
# - CWD (project root; the harness sets it before source)
|
|
19
|
+
#
|
|
20
|
+
# Per @luminary saltzer-schroeder — complete mediation. Every settings
|
|
21
|
+
# entry gets checked, not sampled.
|
|
22
|
+
# Per @luminary linus-torvalds — we do not break adopters. A missing hook
|
|
23
|
+
# is a silent break of the adopter contract; this check surfaces it.
|
|
24
|
+
#
|
|
25
|
+
# Override path — operator can bypass per-session.
|
|
26
|
+
if [ "${SKIP_SETTINGS_HOOK_VERIFY:-0}" = "1" ]; then
|
|
27
|
+
trace_log "skip" "settings-hook-verify" "SKIP_SETTINGS_HOOK_VERIFY=1" 2>/dev/null || true
|
|
28
|
+
return 0 2>/dev/null || true
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Require jq for JSON parsing. Skip silently when absent (rare).
|
|
32
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
33
|
+
trace_log "skip" "settings-hook-verify" "jq not available" 2>/dev/null || true
|
|
34
|
+
return 0 2>/dev/null || true
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
__shv_settings_files=""
|
|
38
|
+
__shv_project_settings="${CWD:-${PWD}}/.claude/settings.json"
|
|
39
|
+
if [ -f "$__shv_project_settings" ]; then
|
|
40
|
+
__shv_settings_files="$__shv_project_settings"
|
|
41
|
+
fi
|
|
42
|
+
__shv_user_settings="${HOME}/.claude/settings.json"
|
|
43
|
+
if [ -f "$__shv_user_settings" ]; then
|
|
44
|
+
__shv_settings_files="${__shv_settings_files:+${__shv_settings_files}$'\n'}${__shv_user_settings}"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ -z "$__shv_settings_files" ]; then
|
|
48
|
+
trace_log "skip" "settings-hook-verify" "no settings.json readable" 2>/dev/null || true
|
|
49
|
+
unset __shv_settings_files __shv_project_settings __shv_user_settings
|
|
50
|
+
return 0 2>/dev/null || true
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Extract the first token of every hook command across every event class.
|
|
54
|
+
# The command string may be plain path OR `path && next` OR `env=X path`.
|
|
55
|
+
# We take the first whitespace-separated token.
|
|
56
|
+
__shv_missing=""
|
|
57
|
+
__shv_check_file() {
|
|
58
|
+
local raw_cmd="$1"
|
|
59
|
+
local source_file="$2"
|
|
60
|
+
# First token — everything up to the first space, tab, or ampersand.
|
|
61
|
+
local first_token
|
|
62
|
+
first_token=$(printf '%s' "$raw_cmd" | awk '{print $1}')
|
|
63
|
+
# Skip if empty or does not look like a path (starts with quote or brace).
|
|
64
|
+
case "$first_token" in
|
|
65
|
+
''|'{'*|'['*) return 0 ;;
|
|
66
|
+
esac
|
|
67
|
+
# Expand known env vars. Leave others as-is (best effort).
|
|
68
|
+
local expanded="$first_token"
|
|
69
|
+
expanded="${expanded//\$HOME/$HOME}"
|
|
70
|
+
expanded="${expanded//\$\{HOME\}/$HOME}"
|
|
71
|
+
expanded="${expanded//\$CLAUDE_PROJECT_DIR/${CWD:-${PWD}}}"
|
|
72
|
+
expanded="${expanded//\$\{CLAUDE_PROJECT_DIR\}/${CWD:-${PWD}}}"
|
|
73
|
+
# If still has an unexpanded $VAR, skip (cannot verify with confidence).
|
|
74
|
+
case "$expanded" in
|
|
75
|
+
*'$'*) return 0 ;;
|
|
76
|
+
esac
|
|
77
|
+
# Absolute path required for the check.
|
|
78
|
+
case "$expanded" in
|
|
79
|
+
/*) : ;;
|
|
80
|
+
*) return 0 ;;
|
|
81
|
+
esac
|
|
82
|
+
if [ ! -f "$expanded" ]; then
|
|
83
|
+
__shv_missing="${__shv_missing:+${__shv_missing}$'\n'} - ${expanded} (from ${source_file})"
|
|
84
|
+
fi
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
__shv_scan_settings() {
|
|
88
|
+
local settings="$1"
|
|
89
|
+
local raw
|
|
90
|
+
# Extract every .hooks.*[].hooks[].command as one line per command.
|
|
91
|
+
raw=$(jq -r '
|
|
92
|
+
.hooks // {}
|
|
93
|
+
| to_entries[]?
|
|
94
|
+
| .value[]?
|
|
95
|
+
| .hooks[]?
|
|
96
|
+
| select(.command != null)
|
|
97
|
+
| .command
|
|
98
|
+
' "$settings" 2>/dev/null)
|
|
99
|
+
if [ -z "$raw" ]; then
|
|
100
|
+
return 0
|
|
101
|
+
fi
|
|
102
|
+
local line
|
|
103
|
+
while IFS= read -r line; do
|
|
104
|
+
[ -n "$line" ] && __shv_check_file "$line" "$settings"
|
|
105
|
+
done <<< "$raw"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Scan each settings file.
|
|
109
|
+
while IFS= read -r __shv_file; do
|
|
110
|
+
[ -n "$__shv_file" ] && __shv_scan_settings "$__shv_file"
|
|
111
|
+
done <<< "$__shv_settings_files"
|
|
112
|
+
|
|
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."
|
|
124
|
+
trace_log "fired" "settings-hook-verify" "missing hooks detected" 2>/dev/null || true
|
|
125
|
+
else
|
|
126
|
+
trace_log "pass" "settings-hook-verify" "all wired hooks resolve" 2>/dev/null || true
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
unset __shv_settings_files __shv_project_settings __shv_user_settings \
|
|
130
|
+
__shv_missing __shv_file
|
|
131
|
+
unset -f __shv_check_file __shv_scan_settings
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# .claude/hooks/session-reflection.d/95-telemetry-emit.sh
|
|
3
|
+
# tier: lite
|
|
4
|
+
# install-class: dual
|
|
5
|
+
#
|
|
6
|
+
# Session-start telemetry emit fragment (bet 2026-07-31f Step 4).
|
|
7
|
+
#
|
|
8
|
+
# Emits `session_start` event when opt-in is ON. If no prior events file
|
|
9
|
+
# exists, also emits an `install_probe` event once — this is the first-
|
|
10
|
+
# session marker used to correlate install source.
|
|
11
|
+
#
|
|
12
|
+
# Silent-fail per @luminary michael-nygard R1 — never crashes session start.
|
|
13
|
+
|
|
14
|
+
# Coordinator-side helpers are provided by the parent session-reflection loop.
|
|
15
|
+
# When sourced from that context, `blocked_banner` + `trace_log` + `BASSCLEF_DIR`
|
|
16
|
+
# are already in scope. When run standalone, we no-op the helpers to stay safe.
|
|
17
|
+
|
|
18
|
+
if ! declare -F trace_log >/dev/null 2>&1; then
|
|
19
|
+
trace_log() { :; }
|
|
20
|
+
fi
|
|
21
|
+
BASSCLEF_DIR="${BASSCLEF_DIR:-${CWD:-$PWD}}"
|
|
22
|
+
|
|
23
|
+
# Probe bundled lib path first (dist/lite/ ship path per #1631 goal
|
|
24
|
+
# 2026-09-14b), then $BASSCLEF_DIR fallback for synced adopters.
|
|
25
|
+
# Pattern matches session-reflection.sh:13.
|
|
26
|
+
_sd="$(dirname "${BASH_SOURCE[0]:-$0}")"
|
|
27
|
+
TL_LIB=""
|
|
28
|
+
for _c in "${_sd}/../../../lib/telemetry.sh" \
|
|
29
|
+
"$BASSCLEF_DIR/lib/telemetry.sh"; do
|
|
30
|
+
[ -f "$_c" ] && TL_LIB="$_c" && break
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# Fire in a silent-fail block so any error here does not crash session start.
|
|
34
|
+
{
|
|
35
|
+
# Only fire when the lib exists (adopter has telemetry enabled)
|
|
36
|
+
if [ -n "$TL_LIB" ]; then
|
|
37
|
+
# shellcheck source=/dev/null
|
|
38
|
+
source "$TL_LIB" 2>/dev/null || return 0 2>/dev/null || exit 0
|
|
39
|
+
|
|
40
|
+
if telemetry_is_enabled; then
|
|
41
|
+
sid=$(telemetry_session_id)
|
|
42
|
+
today=$(date -u +%Y%m%d)
|
|
43
|
+
events_dir="$BASSCLEF_DIR/state/telemetry"
|
|
44
|
+
|
|
45
|
+
# Install probe fires once per install — check if any prior events exist
|
|
46
|
+
if ! compgen -G "$events_dir/events-*.jsonl" >/dev/null 2>&1; then
|
|
47
|
+
# First session ever — emit install_probe (source: unknown for MVP)
|
|
48
|
+
install_source="unknown"
|
|
49
|
+
[ -d "$BASSCLEF_DIR/node_modules/@thebassclef" ] && install_source="npm"
|
|
50
|
+
[ -f "$BASSCLEF_DIR/.git/HEAD" ] && install_source="github-clone"
|
|
51
|
+
|
|
52
|
+
uid=$(uuidgen 2>/dev/null | tr '[:upper:]' '[:lower:]' || echo "00000000-0000-4000-8000-000000000000")
|
|
53
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
54
|
+
telemetry_emit "{\"event_type\":\"install_probe\",\"event_id\":\"$uid\",\"session_id\":\"$sid\",\"timestamp\":\"$ts\",\"tier\":\"lite\",\"payload\":{\"install_source\":\"$install_source\"}}"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Emit session_start
|
|
58
|
+
uid=$(uuidgen 2>/dev/null | tr '[:upper:]' '[:lower:]' || echo "00000000-0000-4000-8000-000000000001")
|
|
59
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
60
|
+
telemetry_emit "{\"event_type\":\"session_start\",\"event_id\":\"$uid\",\"session_id\":\"$sid\",\"timestamp\":\"$ts\",\"tier\":\"lite\",\"payload\":{}}"
|
|
61
|
+
trace_log "95-telemetry-emit: session_start emitted for session $sid"
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
} 2>/dev/null || true
|
|
65
|
+
|
|
66
|
+
return 0 2>/dev/null || exit 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: dual
|
|
4
|
+
#
|
|
5
|
+
# 97-install-class-dispatch.sh — fragment that sources the install-class
|
|
6
|
+
# dispatch libs so the source-graph closure walker discovers them at
|
|
7
|
+
# build time (per scripts/build-adopter-tree.sh).
|
|
8
|
+
#
|
|
9
|
+
# Behavior today (V0 — goal 14c Steps 0-4 landed):
|
|
10
|
+
# - Sources lib/hook-header-parser.sh + lib/hook-installer.sh + lib/source-graph-walker.sh
|
|
11
|
+
# - Does NOT call install_by_class yet — Steps 5-6 extend this fragment
|
|
12
|
+
# to iterate substrate hooks and dispatch
|
|
13
|
+
#
|
|
14
|
+
# Why source-without-call:
|
|
15
|
+
# - Walker discovers libs via source-graph closure (per canvas Stage 2)
|
|
16
|
+
# - LITE_LIBS ships the 3 libs to dist/lite/lib/
|
|
17
|
+
# - Walker+LITE_LIBS sync check requires walker to find every LITE_LIBS entry
|
|
18
|
+
# - Sourcing without calling makes the libs walker-discoverable without
|
|
19
|
+
# changing SessionStart behavior — belt-and-braces for the Step 5-6 wire
|
|
20
|
+
#
|
|
21
|
+
# Silent-fail per ADR-050 R7 — never crash SessionStart on lib source failure
|
|
22
|
+
|
|
23
|
+
_ICD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
|
|
25
|
+
# Source each dispatch lib. Bundled path first (dist/lite/lib/), $BASSCLEF_DIR fallback.
|
|
26
|
+
# Static .sh literals so scripts/build-adopter-tree.sh source-graph walker discovers them.
|
|
27
|
+
|
|
28
|
+
# hook-header-parser.sh
|
|
29
|
+
if [ -f "$_ICD_SCRIPT_DIR/../../../lib/hook-header-parser.sh" ]; then
|
|
30
|
+
# shellcheck source=/dev/null
|
|
31
|
+
{ source "$_ICD_SCRIPT_DIR/../../../lib/hook-header-parser.sh"; } 2>/dev/null || true
|
|
32
|
+
elif [ -f "${BASSCLEF_DIR:-}/lib/hook-header-parser.sh" ]; then
|
|
33
|
+
# shellcheck source=/dev/null
|
|
34
|
+
{ source "${BASSCLEF_DIR:-}/lib/hook-header-parser.sh"; } 2>/dev/null || true
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# hook-installer.sh
|
|
38
|
+
if [ -f "$_ICD_SCRIPT_DIR/../../../lib/hook-installer.sh" ]; then
|
|
39
|
+
# shellcheck source=/dev/null
|
|
40
|
+
{ source "$_ICD_SCRIPT_DIR/../../../lib/hook-installer.sh"; } 2>/dev/null || true
|
|
41
|
+
elif [ -f "${BASSCLEF_DIR:-}/lib/hook-installer.sh" ]; then
|
|
42
|
+
# shellcheck source=/dev/null
|
|
43
|
+
{ source "${BASSCLEF_DIR:-}/lib/hook-installer.sh"; } 2>/dev/null || true
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# source-graph-walker.sh
|
|
47
|
+
if [ -f "$_ICD_SCRIPT_DIR/../../../lib/source-graph-walker.sh" ]; then
|
|
48
|
+
# shellcheck source=/dev/null
|
|
49
|
+
{ source "$_ICD_SCRIPT_DIR/../../../lib/source-graph-walker.sh"; } 2>/dev/null || true
|
|
50
|
+
elif [ -f "${BASSCLEF_DIR:-}/lib/source-graph-walker.sh" ]; then
|
|
51
|
+
# shellcheck source=/dev/null
|
|
52
|
+
{ source "${BASSCLEF_DIR:-}/lib/source-graph-walker.sh"; } 2>/dev/null || true
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Steps 5-6 will extend below with actual install_by_class calls per
|
|
56
|
+
# goal 2026-09-14c step sequencing (docs/iteration-bets/2026-09-14c-*.md).
|
|
57
|
+
# Today the fragment sources-without-calls to satisfy walker discovery.
|