@thebassclef/lite 1.1.0 → 1.2.0-alpha.1
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 +258 -63
- package/dist/cli.js +258 -63
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/bassclef-configs.jsonc +56 -0
- package/dist/lite/.claude/bassclef-orientation.md +120 -0
- package/dist/lite/.claude/hooks/adr-discipline-check.sh +132 -0
- package/dist/lite/.claude/hooks/atomic-pr-check.sh +169 -0
- package/dist/lite/.claude/hooks/auto-save-idle.sh +51 -0
- package/dist/lite/.claude/hooks/bassclef-sync.sh +51 -13
- package/dist/lite/.claude/hooks/bet-doc-gate.sh +283 -0
- package/dist/lite/.claude/hooks/bug-diagnosis.sh +64 -0
- package/dist/lite/.claude/hooks/destructive-command-guard.sh +136 -0
- package/dist/lite/.claude/hooks/file-rename-discipline-check.sh +147 -0
- package/dist/lite/.claude/hooks/hook-classifier-canary.sh +158 -0
- package/dist/lite/.claude/hooks/kiss-default-check.sh +129 -0
- package/dist/lite/.claude/hooks/multi-tenancy-check.sh +83 -0
- package/dist/lite/.claude/hooks/oo-ad-entry-point-check.sh +216 -0
- package/dist/lite/.claude/hooks/operator-private-path-check.sh +203 -0
- package/dist/lite/.claude/hooks/pattern-annotation-validate.sh +142 -0
- package/dist/lite/.claude/hooks/plain-english-steering.sh +15 -1
- package/dist/lite/.claude/hooks/post-write-trace.sh +66 -0
- package/dist/lite/.claude/hooks/pr-body-scrub-check.sh +446 -0
- package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +137 -0
- package/dist/lite/.claude/hooks/pre-gh-pr-body-scrub.sh +192 -0
- package/dist/lite/.claude/hooks/pre-gh-pr-title-scrub.sh +172 -0
- package/dist/lite/.claude/hooks/role-entry-gate.sh +115 -0
- package/dist/lite/.claude/hooks/save-state.sh +268 -0
- package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +8 -1
- package/dist/lite/.claude/hooks/session-reflection.d/10-abrupt-stop-recovery.sh +52 -0
- package/dist/lite/.claude/hooks/session-reflection.d/55-orientation-gate.sh +40 -4
- package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +12 -5
- package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +18 -2
- package/dist/lite/.claude/hooks/session-reflection.d/91-npm-version-drift.sh +54 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/10-abrupt-stop-recovery.test.sh +95 -0
- package/dist/lite/.claude/hooks/session-reflection.sh +62 -15
- package/dist/lite/.claude/hooks/tool-failure-diagnosis.sh +50 -0
- package/dist/lite/.claude/luminaries/andrej-karpathy.md +165 -0
- package/dist/lite/.claude/luminaries/dave-gray.md +155 -0
- package/dist/lite/.claude/luminaries/gary-klein.md +166 -0
- package/dist/lite/.claude/luminaries/kaoru-ishikawa.md +162 -0
- package/dist/lite/.claude/luminaries/lean-product-canvas.md +33 -0
- package/dist/lite/.claude/luminaries/luke-wroblewski.md +224 -0
- package/dist/lite/.claude/luminaries/ryan-singer.md +113 -0
- package/dist/lite/.claude/luminaries/steve-krug.md +168 -0
- package/dist/lite/.claude/luminaries/tony-ulwick.md +134 -0
- package/dist/lite/.claude/rules/arc-level-orientation-before-leaf.md +60 -0
- package/dist/lite/.claude/rules/architect-review-discipline.md +71 -0
- package/dist/lite/.claude/rules/auto-fix-criteria.md +126 -0
- package/dist/lite/.claude/rules/bassclef-hook-drift-blocker.md +144 -0
- package/dist/lite/.claude/rules/bassclef-models-discovery.md +107 -0
- package/dist/lite/.claude/rules/bassclef-workflow-parity.md +104 -0
- package/dist/lite/.claude/rules/cost-governance.md +154 -0
- package/dist/lite/.claude/rules/file-rename-discipline.md +95 -0
- package/dist/lite/.claude/rules/mechanism-fidelity.md +88 -0
- package/dist/lite/.claude/rules/prototype-production-coupling.md +125 -0
- package/dist/lite/.claude/rules/quick-fix-criteria.md +90 -0
- package/dist/lite/.claude/rules/session-artifacts.md +30 -0
- package/dist/lite/.claude/rules/sibling-smoke-after-substrate-change.md +107 -0
- package/dist/lite/.claude/rules/substrate-as-system.md +67 -0
- package/dist/lite/.claude/rules/usability.md +22 -0
- package/dist/lite/.claude/settings.json +20 -0
- package/dist/lite/.claude/skills/agent-research-spawn/SKILL.md +100 -0
- package/dist/lite/.claude/skills/architect-review/SKILL.md +201 -0
- package/dist/lite/.claude/skills/auto-fix/SKILL.md +297 -0
- package/dist/lite/.claude/skills/autonomous/SKILL.md +300 -0
- package/dist/lite/.claude/skills/bind-subdomain/SKILL.md +232 -0
- package/dist/lite/.claude/skills/canvas/SKILL.md +41 -0
- package/dist/lite/.claude/skills/deploy-prod/SKILL.md +106 -0
- package/dist/lite/.claude/skills/docs-sync/SKILL.md +188 -0
- package/dist/lite/.claude/skills/eisenhower/SKILL.md +273 -0
- package/dist/lite/.claude/skills/empathy-map/SKILL.md +168 -0
- package/dist/lite/.claude/skills/frontend-design/SKILL.md +53 -0
- package/dist/lite/.claude/skills/interview-me/SKILL.md +171 -0
- package/dist/lite/.claude/skills/journal-export/SKILL.md +293 -0
- package/dist/lite/.claude/skills/jtbd-tasks/SKILL.md +203 -0
- package/dist/lite/.claude/skills/objectory-decompose/SKILL.md +256 -0
- package/dist/lite/.claude/skills/pick-luminaries/SKILL.md +100 -0
- package/dist/lite/.claude/skills/pre-mortem/SKILL.md +180 -0
- package/dist/lite/.claude/skills/prototype-gallery/SKILL.md +264 -0
- package/dist/lite/.claude/skills/provision-deploy-host/SKILL.md +257 -0
- package/dist/lite/.claude/skills/quick-fix/SKILL.md +273 -0
- package/dist/lite/.claude/skills/release/SKILL.md +311 -0
- package/dist/lite/.claude/skills/release-notes/SKILL.md +202 -0
- package/dist/lite/.claude/skills/rfc/SKILL.md +222 -0
- package/dist/lite/.claude/skills/riff-prototypes/SKILL.md +637 -0
- package/dist/lite/.claude/skills/secrets-bootstrap/SKILL.md +209 -0
- package/dist/lite/.claude/skills/skill/SKILL.md +304 -0
- package/dist/lite/.claude/skills/smoke-test/SKILL.md +100 -0
- package/dist/lite/.claude/skills/state/SKILL.md +204 -0
- package/dist/lite/.claude/skills/substrate-check/SKILL.md +218 -0
- package/dist/lite/.claude/skills/synthetic-user/SKILL.md +381 -0
- package/dist/lite/.claude/skills/task-scenarios/SKILL.md +105 -0
- package/dist/lite/.claude/skills/tier-dependency-audit/SKILL.md +139 -0
- package/dist/lite/.claude/skills/ux-migration/SKILL.md +424 -0
- package/dist/lite/.claude/skills/value-prop-canvas/SKILL.md +297 -0
- package/dist/lite/README.md +5 -1
- package/dist/lite/gitignore +6 -0
- package/dist/lite/lib/bassclef-dir-resolver.sh +85 -0
- package/dist/lite/lib/clone-failure-classifier.sh +59 -0
- package/dist/lite/lib/fixture-builder.sh +190 -0
- package/dist/lite/lib/fresh-install-check.sh +49 -0
- package/dist/lite/lib/hook-heartbeat.sh +0 -1
- package/dist/lite/lib/mechanism-fidelity.sh +569 -0
- package/dist/lite/lib/npm-version-check.sh +112 -0
- package/dist/lite/lib/preview-state.sh +229 -0
- package/dist/lite/lib/session-rescue.sh +0 -1
- package/dist/lite/scripts/generate-lite-manifest.sh +145 -4
- package/dist/lite/scripts/lite-manifest-drift-check.sh +5 -1
- package/dist/lite/standards/architect-review-discipline.md +222 -0
- package/dist/lite/standards/bassclef-platform.md +249 -0
- package/dist/lite/standards/bassclef-test-repos.md +97 -0
- package/dist/lite/standards/bassclef-wiring-manifest.json +25 -1
- package/dist/lite/standards/cold-adopter-harness.md +205 -0
- package/dist/lite/standards/data-management.md +135 -0
- package/dist/lite/standards/frontend-stack/nextjs-prisma.md +124 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +27 -0
- package/dist/lite/standards/lite-manifest.json +1456 -14
- package/dist/lite/standards/mechanism-fidelity.md +205 -0
- package/dist/lite/standards/operator-private-discipline.md +200 -0
- package/dist/lite/standards/operator-to-public-flow.md +195 -0
- package/dist/lite/standards/prototype-gallery.md +251 -0
- package/dist/lite/standards/pseudonym-key-schema.md +109 -0
- package/dist/lite/standards/sibling-validation-checklist.md +181 -0
- package/dist/lite/standards/slack-notifications.md +161 -0
- package/dist/lite/standards/synthetic-user-testing.md +173 -0
- package/dist/lite/standards/vendor-bindings.md +165 -0
- package/dist/lite/standards/vendor-plugins/frontend-design.md +66 -0
- package/dist/lite/standards/vpc-fit-validation.md +167 -0
- package/dist/lite/templates/gallery-yml.md +113 -0
- package/dist/lite/templates/product-canvas.md +169 -0
- package/dist/lite/templates/value-prop-canvas.md +180 -0
- package/package.json +12 -5
- /package/dist/lite/{whereami.md → docs/whereami.md} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: project
|
|
4
|
+
# hook-classifier-canary.sh — advises author when a new hook lands
|
|
5
|
+
# without any recognized wiring (settings.json / .github/workflows /
|
|
6
|
+
# scripts/release-to-bassclef.sh / launchd header / sourced-lib
|
|
7
|
+
# header). Fires at PreToolUse on Edit|Write against paths under
|
|
8
|
+
# .claude/hooks/*.sh.
|
|
9
|
+
#
|
|
10
|
+
# Layer 4 cure for sunj-labs/bassclef-upstream#1163. Same class as
|
|
11
|
+
# the hook-wire-on-author rule; extends discipline to catch mislabels
|
|
12
|
+
# at author time — not release time.
|
|
13
|
+
#
|
|
14
|
+
# Anchors: @luminary saltzer-schroeder (complete mediation at earliest
|
|
15
|
+
# cheap gate), @luminary david-parnas (canary hides classifier
|
|
16
|
+
# vocabulary from author), @luminary michael-feathers (characterization
|
|
17
|
+
# tests pin behavior at author boundary).
|
|
18
|
+
#
|
|
19
|
+
# Reads stdin JSON per Claude Code hook contract:
|
|
20
|
+
# { "tool_name": "Edit|Write", "tool_input": { "file_path": "..." } }
|
|
21
|
+
#
|
|
22
|
+
# Exit codes:
|
|
23
|
+
# 0 — pass (V1 ADVISORY only writes to stderr; V2 may flip to BLOCK)
|
|
24
|
+
# 2 — reserved for V2 BLOCK escalation
|
|
25
|
+
#
|
|
26
|
+
# Override:
|
|
27
|
+
# SKIP_HOOK_CLASSIFIER_CANARY=1 bypass; logged via trace-helper
|
|
28
|
+
|
|
29
|
+
set -uo pipefail
|
|
30
|
+
|
|
31
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
32
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
33
|
+
|
|
34
|
+
# Override
|
|
35
|
+
if [ "${SKIP_HOOK_CLASSIFIER_CANARY:-}" = "1" ]; then
|
|
36
|
+
TRACE_HELPER="$SCRIPT_DIR/trace-helper.sh"
|
|
37
|
+
if [ -f "$TRACE_HELPER" ]; then
|
|
38
|
+
# shellcheck disable=SC1090
|
|
39
|
+
source "$TRACE_HELPER" 2>/dev/null || true
|
|
40
|
+
trace_record "hook-classifier-canary" "skipped via SKIP_HOOK_CLASSIFIER_CANARY=1" 2>/dev/null || true
|
|
41
|
+
fi
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Read stdin JSON. If jq not available, degrade gracefully.
|
|
46
|
+
INPUT=$(cat)
|
|
47
|
+
if [ -z "$INPUT" ]; then
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if command -v jq >/dev/null 2>&1; then
|
|
52
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
|
|
53
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")
|
|
54
|
+
else
|
|
55
|
+
# Fallback — crude sed parse
|
|
56
|
+
TOOL_NAME=$(echo "$INPUT" | sed -n 's/.*"tool_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
|
57
|
+
FILE_PATH=$(echo "$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Pass-through — non-Edit/Write tools
|
|
61
|
+
case "$TOOL_NAME" in
|
|
62
|
+
Edit|Write|MultiEdit) ;;
|
|
63
|
+
*) exit 0 ;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
# Pass-through — no file path
|
|
67
|
+
[ -z "$FILE_PATH" ] && exit 0
|
|
68
|
+
|
|
69
|
+
# Pass-through — path outside .claude/hooks/*.sh
|
|
70
|
+
case "$FILE_PATH" in
|
|
71
|
+
*/.claude/hooks/*.sh) ;;
|
|
72
|
+
*) exit 0 ;;
|
|
73
|
+
esac
|
|
74
|
+
|
|
75
|
+
# Pass-through — path is under .claude/hooks/tests/ or fixtures
|
|
76
|
+
case "$FILE_PATH" in
|
|
77
|
+
*/.claude/hooks/tests/*|*/.claude/hooks/*/tests/*) exit 0 ;;
|
|
78
|
+
esac
|
|
79
|
+
|
|
80
|
+
# Get bare hook name for classifier lookup
|
|
81
|
+
HOOK_NAME=$(basename "$FILE_PATH")
|
|
82
|
+
|
|
83
|
+
# Pass-through — this file exists on disk already (edit, not new)
|
|
84
|
+
if [ -f "$FILE_PATH" ]; then
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Load classifier
|
|
89
|
+
LIB="$REPO_ROOT/lib/mechanism-fidelity.sh"
|
|
90
|
+
if [ ! -f "$LIB" ]; then
|
|
91
|
+
# Classifier lib missing — cannot advise; pass silently
|
|
92
|
+
exit 0
|
|
93
|
+
fi
|
|
94
|
+
# shellcheck disable=SC1090
|
|
95
|
+
source "$LIB"
|
|
96
|
+
|
|
97
|
+
# Ask classifier what pattern it detects for this hook name
|
|
98
|
+
PATTERN=$(classify_hook_install_pattern "$HOOK_NAME" "$REPO_ROOT" 2>/dev/null)
|
|
99
|
+
|
|
100
|
+
# Recognized patterns → pass
|
|
101
|
+
case "$PATTERN" in
|
|
102
|
+
ci|launchd|lib|release)
|
|
103
|
+
exit 0
|
|
104
|
+
;;
|
|
105
|
+
esac
|
|
106
|
+
|
|
107
|
+
# Standard means classifier could not place it AND file does not exist yet.
|
|
108
|
+
# Check settings.json — hook may be wired for PreToolUse there.
|
|
109
|
+
SETTINGS="$REPO_ROOT/.claude/settings.json"
|
|
110
|
+
if [ -f "$SETTINGS" ] && grep -qF "$HOOK_NAME" "$SETTINGS" 2>/dev/null; then
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# No recognized wiring signal found. Emit ADVISORY.
|
|
115
|
+
cat >&2 <<EOF
|
|
116
|
+
|
|
117
|
+
============================================
|
|
118
|
+
🚨 hook-classifier-canary — ADVISORY
|
|
119
|
+
============================================
|
|
120
|
+
|
|
121
|
+
New hook detected: $HOOK_NAME
|
|
122
|
+
Author path: $FILE_PATH
|
|
123
|
+
|
|
124
|
+
The classifier at lib/mechanism-fidelity.sh does not recognize any
|
|
125
|
+
wiring signal for this hook. If this ships as-is, the cold-adopter
|
|
126
|
+
harness Shape d checks will flag it as DEAD-LETTER.
|
|
127
|
+
|
|
128
|
+
Five remediation paths (pick one before commit):
|
|
129
|
+
|
|
130
|
+
1. settings.json wiring — add hook entry to .claude/settings.json
|
|
131
|
+
under PreToolUse/PostToolUse/SessionStart/Stop event matcher.
|
|
132
|
+
For hooks that fire on tool calls.
|
|
133
|
+
|
|
134
|
+
2. CI workflow — reference the hook name in a .github/workflows/*.yml
|
|
135
|
+
file. For hooks that fire on push/PR events.
|
|
136
|
+
|
|
137
|
+
3. Release script — reference the hook name in
|
|
138
|
+
scripts/release-to-bassclef.sh. For hooks that gate on /release
|
|
139
|
+
dispatch. Classifier returns "release".
|
|
140
|
+
|
|
141
|
+
4. launchd header — add "# Runs via launchd" (or "scheduled job" /
|
|
142
|
+
"cron job") to the hook's top-of-file comment block. For
|
|
143
|
+
scheduled jobs. Classifier returns "launchd".
|
|
144
|
+
|
|
145
|
+
5. Sourced-library header — add "# sourced by <caller>" to the
|
|
146
|
+
hook's top-of-file comment block. For helper libraries loaded
|
|
147
|
+
via source. Classifier returns "lib".
|
|
148
|
+
|
|
149
|
+
If genuinely bypassing (rare): SKIP_HOOK_CLASSIFIER_CANARY=1 <command>
|
|
150
|
+
|
|
151
|
+
Per rule: .claude/rules/hook-wire-on-author.md
|
|
152
|
+
Per Layer 4 of: bassclef-upstream#1163
|
|
153
|
+
============================================
|
|
154
|
+
|
|
155
|
+
EOF
|
|
156
|
+
|
|
157
|
+
# V1 — ADVISORY only. V2 may flip to exit 2 (BLOCK).
|
|
158
|
+
exit 0
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: project
|
|
4
|
+
# kiss-default-check.sh — pre-push /kiss enforcement check
|
|
5
|
+
# Per bassclef#907 Part 4.
|
|
6
|
+
#
|
|
7
|
+
# Reads a draft body file. Checks for BLOCK-tier bassclef-internal jargon
|
|
8
|
+
# per standards/bassclef-internal-jargon.md. BLOCKs if jargon present and
|
|
9
|
+
# no opt-out signal.
|
|
10
|
+
#
|
|
11
|
+
# Composes with .claude/hooks/pr-body-scrub-check.sh (CI-time enforcement).
|
|
12
|
+
# This hook runs pre-push; the scrub hook runs at CI. Both read the same
|
|
13
|
+
# BLOCK list from the standards source-of-truth.
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# bash kiss-default-check.sh <body-file>
|
|
17
|
+
#
|
|
18
|
+
# Optional env:
|
|
19
|
+
# PR_LABELS=label1,label2,... — labels on the PR (newline or comma separated)
|
|
20
|
+
# SKIP_KISS=1 — operator opt-out for one invocation
|
|
21
|
+
# KISS_STANDARDS_FILE=<path> — override standards file location (testing)
|
|
22
|
+
#
|
|
23
|
+
# Exit codes:
|
|
24
|
+
# 0 — pass (no BLOCK terms found, OR opt-out signal present)
|
|
25
|
+
# 1 — block (BLOCK terms found + no opt-out)
|
|
26
|
+
# 2 — usage error
|
|
27
|
+
|
|
28
|
+
set +e
|
|
29
|
+
|
|
30
|
+
BODY_FILE="${1:-}"
|
|
31
|
+
if [ -z "$BODY_FILE" ] || [ ! -f "$BODY_FILE" ]; then
|
|
32
|
+
echo "usage: $0 <body-file>" >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Find the repo root + standards file
|
|
37
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
39
|
+
STANDARDS_FILE="${KISS_STANDARDS_FILE:-$REPO_ROOT/standards/bassclef-internal-jargon.md}"
|
|
40
|
+
|
|
41
|
+
if [ ! -f "$STANDARDS_FILE" ]; then
|
|
42
|
+
# Try the bassclef-sync'd path (when run from a consumer repo)
|
|
43
|
+
STANDARDS_FILE="${HOME}/src/sunj-labs/bassclef/standards/bassclef-internal-jargon.md"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [ ! -f "$STANDARDS_FILE" ]; then
|
|
47
|
+
echo "kiss-default-check: standards file not found at $STANDARDS_FILE" >&2
|
|
48
|
+
echo " set KISS_STANDARDS_FILE=<path> or skip this check" >&2
|
|
49
|
+
exit 2
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Opt-out — env var
|
|
53
|
+
if [ "${SKIP_KISS:-0}" = "1" ]; then
|
|
54
|
+
echo "kiss-default-check: SKIP_KISS=1 — skipped (logged)" >&2
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Opt-out — label
|
|
59
|
+
PR_LABELS="${PR_LABELS:-}"
|
|
60
|
+
LABELS_NORMALIZED=$(echo "$PR_LABELS" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | grep -v '^$' || true)
|
|
61
|
+
if echo "$LABELS_NORMALIZED" | grep -qx "bassclef-internal-prose-ok"; then
|
|
62
|
+
echo "kiss-default-check: bassclef-internal-prose-ok label — advisory mode" >&2
|
|
63
|
+
ADVISORY=1
|
|
64
|
+
else
|
|
65
|
+
ADVISORY=0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Extract BLOCK terms from the standards table
|
|
69
|
+
# The standards table has lines like: | term | plain-english | BLOCK |
|
|
70
|
+
# Allows digits in the first column so terms like "12-pattern matcher"
|
|
71
|
+
# (added under bassclef-upstream#101) are picked up.
|
|
72
|
+
BLOCK_TERMS=$(awk -F'|' '
|
|
73
|
+
/^\| [a-zA-Z0-9-]+ / && /BLOCK *\|$/ {
|
|
74
|
+
gsub(/^ +| +$/, "", $2)
|
|
75
|
+
print $2
|
|
76
|
+
}
|
|
77
|
+
' "$STANDARDS_FILE")
|
|
78
|
+
|
|
79
|
+
if [ -z "$BLOCK_TERMS" ]; then
|
|
80
|
+
echo "kiss-default-check: no BLOCK terms found in standards file" >&2
|
|
81
|
+
exit 0
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Strip code blocks + inline backtick spans + URLs so they don't trigger false positives
|
|
85
|
+
SCRUBBED=$(awk '
|
|
86
|
+
BEGIN { in_code = 0 }
|
|
87
|
+
/^```/ { in_code = !in_code; next }
|
|
88
|
+
in_code { next }
|
|
89
|
+
{ print }
|
|
90
|
+
' "$BODY_FILE" | sed -E 's/`[^`]*`//g; s|https?://[^ )]+||g')
|
|
91
|
+
|
|
92
|
+
# Check each BLOCK term
|
|
93
|
+
FINDINGS=""
|
|
94
|
+
FINDING_COUNT=0
|
|
95
|
+
while IFS= read -r term; do
|
|
96
|
+
[ -z "$term" ] && continue
|
|
97
|
+
count=$(echo "$SCRUBBED" | grep -ioE "\\b${term}\\b" | wc -l | tr -d ' ')
|
|
98
|
+
if [ "$count" -gt 0 ]; then
|
|
99
|
+
FINDINGS="${FINDINGS}- \`${term}\` (${count}x)"$'\n'
|
|
100
|
+
FINDING_COUNT=$((FINDING_COUNT + count))
|
|
101
|
+
fi
|
|
102
|
+
done <<< "$BLOCK_TERMS"
|
|
103
|
+
|
|
104
|
+
if [ "$FINDING_COUNT" -eq 0 ]; then
|
|
105
|
+
echo "kiss-default-check: pass — no BLOCK terms in draft" >&2
|
|
106
|
+
exit 0
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Report findings
|
|
110
|
+
{
|
|
111
|
+
echo ""
|
|
112
|
+
echo "kiss-default-check: $FINDING_COUNT BLOCK-tier jargon term(s) found in draft body:"
|
|
113
|
+
echo ""
|
|
114
|
+
echo "$FINDINGS"
|
|
115
|
+
echo "Plain-English alternatives at: $STANDARDS_FILE"
|
|
116
|
+
echo ""
|
|
117
|
+
echo "Options:"
|
|
118
|
+
echo " 1. Run /kiss --grade11 on the draft and re-push"
|
|
119
|
+
echo " 2. Add label 'bassclef-internal-prose-ok' for advisory-only"
|
|
120
|
+
echo " 3. Set SKIP_KISS=1 for one-time bypass (logged)"
|
|
121
|
+
echo ""
|
|
122
|
+
} >&2
|
|
123
|
+
|
|
124
|
+
if [ "$ADVISORY" = "1" ]; then
|
|
125
|
+
echo "kiss-default-check: ADVISORY (label) — passing with warnings" >&2
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
exit 1
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# Multi-Tenancy Check — bassclef template.
|
|
4
|
+
# Fires on Edit/Write of source files.
|
|
5
|
+
# Warns when tenant-scoped patterns are missing.
|
|
6
|
+
#
|
|
7
|
+
# App repos should customize:
|
|
8
|
+
# TENANT_MODELS — pipe-separated list of tenant-scoped model names
|
|
9
|
+
# TENANT_CONTEXT_FN — function name that resolves tenant context
|
|
10
|
+
# TENANT_PARAMS_FN — function name for tenant-specific parameters
|
|
11
|
+
#
|
|
12
|
+
# Override by placing your own multi-tenancy-check.sh in .claude/hooks/
|
|
13
|
+
|
|
14
|
+
INPUT=$(cat)
|
|
15
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.file_path // ""')
|
|
16
|
+
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // ""')
|
|
17
|
+
|
|
18
|
+
# Skip non-source files
|
|
19
|
+
if echo "$FILE_PATH" | grep -qE '\.(sh|json|md)$|/\.claude/|/memory/|/docs/|/scripts/|__tests__'; then
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# === Customizable per project (override these in your app's copy) ===
|
|
24
|
+
TENANT_CONTEXT_FN="${TENANT_CONTEXT_FN:-getTenantContext}"
|
|
25
|
+
TENANT_PARAMS_FN="${TENANT_PARAMS_FN:-getTenantParams}"
|
|
26
|
+
# Default: no models (app must define its own)
|
|
27
|
+
TENANT_MODELS="${TENANT_MODELS:-}"
|
|
28
|
+
|
|
29
|
+
# Skip if no tenant models defined (not a multi-tenant project)
|
|
30
|
+
if [ -z "$TENANT_MODELS" ]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
WARNINGS=""
|
|
35
|
+
|
|
36
|
+
# Check 1: Hardcoded numeric thresholds that should use params facade
|
|
37
|
+
if echo "$CONTENT" | grep -qE '[0-9]{3,}\.?[0-9]*\.?[0-9]*' ; then
|
|
38
|
+
if echo "$CONTENT" | grep -qE '_FLOOR|_CEILING|_THRESHOLD|_LIMIT|_MIN|_MAX'; then
|
|
39
|
+
if ! echo "$CONTENT" | grep -q "$TENANT_PARAMS_FN"; then
|
|
40
|
+
WARNINGS="${WARNINGS}
|
|
41
|
+
MULTI-TENANCY: Possible hardcoded threshold detected.
|
|
42
|
+
Use ${TENANT_PARAMS_FN}() instead of hardcoded values.
|
|
43
|
+
Financial and geographic thresholds must flow through
|
|
44
|
+
the tenant params facade for multi-tenant readiness."
|
|
45
|
+
fi
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Check 2: Prisma queries on tenant-scoped models without context
|
|
50
|
+
if echo "$CONTENT" | grep -qiE "prisma\.(${TENANT_MODELS})\.(findMany|findFirst|create|update|delete)" ; then
|
|
51
|
+
if ! echo "$CONTENT" | grep -q "$TENANT_CONTEXT_FN"; then
|
|
52
|
+
WARNINGS="${WARNINGS}
|
|
53
|
+
MULTI-TENANCY: Query on tenant-scoped model without ${TENANT_CONTEXT_FN}().
|
|
54
|
+
Tenant-scoped models must be filtered by tenant/user context.
|
|
55
|
+
Use ${TENANT_CONTEXT_FN}() and filter appropriately."
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Check 3: API routes missing tenant context
|
|
60
|
+
if echo "$FILE_PATH" | grep -qE 'src/app/api/.*route\.ts'; then
|
|
61
|
+
if echo "$CONTENT" | grep -qE 'export async function (GET|POST|PATCH|DELETE|PUT)'; then
|
|
62
|
+
if ! echo "$CONTENT" | grep -q "$TENANT_CONTEXT_FN"; then
|
|
63
|
+
WARNINGS="${WARNINGS}
|
|
64
|
+
MULTI-TENANCY: API route handler without ${TENANT_CONTEXT_FN}().
|
|
65
|
+
All API routes touching tenant-scoped data must resolve
|
|
66
|
+
tenant context. Even GET routes need this for data isolation."
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [ -n "$WARNINGS" ]; then
|
|
72
|
+
echo "============================================"
|
|
73
|
+
echo "MULTI-TENANCY GUARDRAIL"
|
|
74
|
+
echo "============================================"
|
|
75
|
+
echo "$WARNINGS"
|
|
76
|
+
echo ""
|
|
77
|
+
echo "These are WARNs, not BLOCKs. If this is intentional"
|
|
78
|
+
echo "(e.g., platform-wide data), proceed."
|
|
79
|
+
echo "If tenant-scoped, add the missing context/facade."
|
|
80
|
+
echo "============================================"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
exit 0
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# oo-ad-entry-point-check.sh — PreToolUse Edit/Write hook mechanizing .claude/rules/oo-ad-entry-point.md.
|
|
4
|
+
#
|
|
5
|
+
# Fires on Write to a new file matching the rule's globs. Requires:
|
|
6
|
+
# 1. A decomposition marker at state/markers/decompose/<branch>.marker
|
|
7
|
+
# OR any file under docs/decompositions/
|
|
8
|
+
# 2. A use-case artifact under docs/use-cases/ matching the code class
|
|
9
|
+
#
|
|
10
|
+
# Per bassclef-upstream#1169 + canvas docs/canvases/2026-08-25-ooad-chain-as-substrate-offering.md.
|
|
11
|
+
# Composes with .claude/hooks/adr-discipline-check.sh (sister hook on architectural boundaries).
|
|
12
|
+
# Override: SKIP_OO_AD_ENTRY_POINT=1 (logged via trace-helper).
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
# ============================================================================
|
|
17
|
+
# Read stdin JSON from Claude Code harness
|
|
18
|
+
# ============================================================================
|
|
19
|
+
PAYLOAD=$(cat 2>/dev/null || echo '{}')
|
|
20
|
+
|
|
21
|
+
TOOL_NAME=$(echo "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
22
|
+
FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
23
|
+
|
|
24
|
+
# ============================================================================
|
|
25
|
+
# Filter: only fire on Write / Edit / MultiEdit
|
|
26
|
+
# ============================================================================
|
|
27
|
+
case "$TOOL_NAME" in
|
|
28
|
+
Write|Edit|MultiEdit) ;;
|
|
29
|
+
*) exit 0 ;;
|
|
30
|
+
esac
|
|
31
|
+
|
|
32
|
+
# Defensive precondition — empty file_path
|
|
33
|
+
if [ -z "$FILE_PATH" ]; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Override check
|
|
39
|
+
# ============================================================================
|
|
40
|
+
if [ "${SKIP_OO_AD_ENTRY_POINT:-0}" = "1" ]; then
|
|
41
|
+
TRACE_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/trace-helper.sh"
|
|
42
|
+
if [ -f "$TRACE_HELPER" ]; then
|
|
43
|
+
bash "$TRACE_HELPER" override "oo-ad-entry-point-check" "SKIP_OO_AD_ENTRY_POINT=1 on $FILE_PATH" 2>/dev/null || true
|
|
44
|
+
fi
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# ============================================================================
|
|
49
|
+
# Path matcher — classify code class per rule oo-ad-entry-point.md L18-25
|
|
50
|
+
# Bash case globs do NOT expand ** — use per-level cases + src/ recursive fallback.
|
|
51
|
+
# ============================================================================
|
|
52
|
+
CODE_CLASS=""
|
|
53
|
+
case "$FILE_PATH" in
|
|
54
|
+
*/.claude/hooks/*.sh|.claude/hooks/*.sh)
|
|
55
|
+
CODE_CLASS="substrate-hook"
|
|
56
|
+
;;
|
|
57
|
+
*/lib/*.sh|lib/*.sh)
|
|
58
|
+
CODE_CLASS="substrate-lib"
|
|
59
|
+
;;
|
|
60
|
+
*/scripts/*.sh|scripts/*.sh)
|
|
61
|
+
CODE_CLASS="adopter-script"
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
|
|
65
|
+
# src/ handled via recursive path check — any depth under src/ with .ts/.tsx/.js/.py extension
|
|
66
|
+
if [ -z "$CODE_CLASS" ]; then
|
|
67
|
+
case "$FILE_PATH" in
|
|
68
|
+
src/*|*/src/*)
|
|
69
|
+
case "$FILE_PATH" in
|
|
70
|
+
*.ts|*.tsx|*.js|*.py) CODE_CLASS="adopter-app" ;;
|
|
71
|
+
esac
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Not a matched path → pass through
|
|
77
|
+
if [ -z "$CODE_CLASS" ]; then
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# ============================================================================
|
|
82
|
+
# Cockburn casual tier — existing file Edit passes through
|
|
83
|
+
# ============================================================================
|
|
84
|
+
# Edit / MultiEdit on existing files needs no new artifacts per rule L24.
|
|
85
|
+
# Only new files (Write, OR Edit of missing file) require ceremony.
|
|
86
|
+
REPO_ROOT="${HOOK_TEST_REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
|
87
|
+
|
|
88
|
+
# Resolve absolute path — file_path may be relative
|
|
89
|
+
if [ "${FILE_PATH:0:1}" = "/" ]; then
|
|
90
|
+
ABS_PATH="$FILE_PATH"
|
|
91
|
+
else
|
|
92
|
+
ABS_PATH="$REPO_ROOT/$FILE_PATH"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if [ -f "$ABS_PATH" ]; then
|
|
96
|
+
exit 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# ============================================================================
|
|
100
|
+
# Decomposition check
|
|
101
|
+
# ============================================================================
|
|
102
|
+
BRANCH="${HOOK_TEST_BRANCH:-}"
|
|
103
|
+
if [ -z "$BRANCH" ]; then
|
|
104
|
+
BRANCH=$(cd "$REPO_ROOT" && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
MARKER_PATH="$REPO_ROOT/state/markers/decompose/${BRANCH}.marker"
|
|
108
|
+
DECOMP_DIR="$REPO_ROOT/docs/decompositions"
|
|
109
|
+
|
|
110
|
+
DECOMP_OK=0
|
|
111
|
+
if [ -f "$MARKER_PATH" ]; then
|
|
112
|
+
DECOMP_OK=1
|
|
113
|
+
elif [ -d "$DECOMP_DIR" ] && find "$DECOMP_DIR" -maxdepth 1 -name '*.md' -type f 2>/dev/null | grep -q .; then
|
|
114
|
+
DECOMP_OK=1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# ============================================================================
|
|
118
|
+
# Use case check per code class
|
|
119
|
+
# ============================================================================
|
|
120
|
+
UC_DIR="$REPO_ROOT/docs/use-cases"
|
|
121
|
+
UC_OK=0
|
|
122
|
+
|
|
123
|
+
if [ -d "$UC_DIR" ]; then
|
|
124
|
+
case "$CODE_CLASS" in
|
|
125
|
+
adopter-app)
|
|
126
|
+
# UC-*.md that does NOT start with UC-hook-, UC-lib-, or UC-script-
|
|
127
|
+
if find "$UC_DIR" -maxdepth 1 -name 'UC-*.md' -type f \
|
|
128
|
+
-not -name 'UC-hook-*' -not -name 'UC-lib-*' -not -name 'UC-script-*' \
|
|
129
|
+
2>/dev/null | grep -q .; then
|
|
130
|
+
UC_OK=1
|
|
131
|
+
fi
|
|
132
|
+
;;
|
|
133
|
+
substrate-hook)
|
|
134
|
+
if find "$UC_DIR" -maxdepth 1 -name 'UC-hook-*.md' -type f 2>/dev/null | grep -q .; then
|
|
135
|
+
UC_OK=1
|
|
136
|
+
fi
|
|
137
|
+
;;
|
|
138
|
+
substrate-lib)
|
|
139
|
+
if find "$UC_DIR" -maxdepth 1 -name 'UC-lib-*.md' -type f 2>/dev/null | grep -q .; then
|
|
140
|
+
UC_OK=1
|
|
141
|
+
fi
|
|
142
|
+
;;
|
|
143
|
+
adopter-script)
|
|
144
|
+
if find "$UC_DIR" -maxdepth 1 -name 'UC-script-*.md' -type f 2>/dev/null | grep -q .; then
|
|
145
|
+
UC_OK=1
|
|
146
|
+
fi
|
|
147
|
+
;;
|
|
148
|
+
esac
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# ============================================================================
|
|
152
|
+
# Pass or block
|
|
153
|
+
# ============================================================================
|
|
154
|
+
if [ "$DECOMP_OK" -eq 1 ] && [ "$UC_OK" -eq 1 ]; then
|
|
155
|
+
exit 0
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# ============================================================================
|
|
159
|
+
# Block message
|
|
160
|
+
# ============================================================================
|
|
161
|
+
case "$CODE_CLASS" in
|
|
162
|
+
adopter-app)
|
|
163
|
+
CEREMONY="Fully-dressed use case + /decompose + /spec"
|
|
164
|
+
UC_PATTERN="docs/use-cases/UC-<slug>.md"
|
|
165
|
+
;;
|
|
166
|
+
substrate-hook)
|
|
167
|
+
CEREMONY="Brief use case + /decompose"
|
|
168
|
+
UC_PATTERN="docs/use-cases/UC-hook-<slug>.md"
|
|
169
|
+
;;
|
|
170
|
+
substrate-lib)
|
|
171
|
+
CEREMONY="Brief use case + /decompose"
|
|
172
|
+
UC_PATTERN="docs/use-cases/UC-lib-<slug>.md"
|
|
173
|
+
;;
|
|
174
|
+
adopter-script)
|
|
175
|
+
CEREMONY="Brief use case + Tier 0 tests"
|
|
176
|
+
UC_PATTERN="docs/use-cases/UC-script-<slug>.md"
|
|
177
|
+
;;
|
|
178
|
+
esac
|
|
179
|
+
|
|
180
|
+
cat >&2 <<EOF
|
|
181
|
+
🛑 oo-ad-entry-point-check — BLOCK (bassclef-upstream#1169)
|
|
182
|
+
|
|
183
|
+
You are creating a new file in the ${CODE_CLASS} class.
|
|
184
|
+
|
|
185
|
+
Path: ${FILE_PATH}
|
|
186
|
+
Branch: ${BRANCH}
|
|
187
|
+
|
|
188
|
+
The rule .claude/rules/oo-ad-entry-point.md requires design artifacts
|
|
189
|
+
before this file lands. Ceremony for this class:
|
|
190
|
+
${CEREMONY}
|
|
191
|
+
|
|
192
|
+
Missing artifacts:
|
|
193
|
+
$([ "$DECOMP_OK" -eq 0 ] && echo " - Decomposition: marker at ${MARKER_PATH} OR any file under docs/decompositions/")
|
|
194
|
+
$([ "$UC_OK" -eq 0 ] && echo " - Use case: ${UC_PATTERN}")
|
|
195
|
+
|
|
196
|
+
Three resolution paths:
|
|
197
|
+
|
|
198
|
+
1. Run /decompose to produce the decomposition, then write a use case.
|
|
199
|
+
Touch the marker after:
|
|
200
|
+
mkdir -p $(dirname "$MARKER_PATH")
|
|
201
|
+
touch $MARKER_PATH
|
|
202
|
+
|
|
203
|
+
2. Write the artifacts by hand per the rule table (L18-25) and touch
|
|
204
|
+
the marker.
|
|
205
|
+
|
|
206
|
+
3. Override for genuine trivial work:
|
|
207
|
+
SKIP_OO_AD_ENTRY_POINT=1 <command>
|
|
208
|
+
|
|
209
|
+
Then retry the original write.
|
|
210
|
+
|
|
211
|
+
Per .claude/rules/oo-ad-entry-point.md
|
|
212
|
+
Composes with .claude/hooks/adr-discipline-check.sh
|
|
213
|
+
Cockburn ceremony tiering — Writing Effective Use Cases (2000)
|
|
214
|
+
EOF
|
|
215
|
+
|
|
216
|
+
exit 2
|