@thebassclef/lite 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +85 -4
  3. package/dist/cli.cjs +1610 -0
  4. package/dist/cli.js +1587 -0
  5. package/dist/index.cjs +4 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +4 -0
  8. package/package.json +51 -3
  9. package/substrate/.bassclef/lite-manifest.json +1794 -0
  10. package/substrate/.claude/agents/architect.md +70 -0
  11. package/substrate/.claude/agents/builder.md +114 -0
  12. package/substrate/.claude/agents/designer.md +156 -0
  13. package/substrate/.claude/agents/reviewer.md +88 -0
  14. package/substrate/.claude/hooks/artifact-ingestion-gate.sh +357 -0
  15. package/substrate/.claude/hooks/assert-verify-steering.sh +77 -0
  16. package/substrate/.claude/hooks/bassclef-source-config-validate.sh +215 -0
  17. package/substrate/.claude/hooks/bassclef-sync.sh +634 -0
  18. package/substrate/.claude/hooks/compound-noun-scrub.sh +292 -0
  19. package/substrate/.claude/hooks/kiss-expansion-inject.sh +69 -0
  20. package/substrate/.claude/hooks/plain-english-steering.sh +156 -0
  21. package/substrate/.claude/hooks/post-skill-friction-check.sh +177 -0
  22. package/substrate/.claude/hooks/post-skill-telemetry.sh +62 -0
  23. package/substrate/.claude/hooks/pre-build-gate.sh +511 -0
  24. package/substrate/.claude/hooks/pre-commit-gate.sh +452 -0
  25. package/substrate/.claude/hooks/session-end.sh +433 -0
  26. package/substrate/.claude/hooks/session-reflection.sh +303 -0
  27. package/substrate/.claude/hooks/skill-body-grade-gate.sh +219 -0
  28. package/substrate/.claude/hooks/skill-body-intent-drift.sh +107 -0
  29. package/substrate/.claude/hooks/skill-step-list-check.sh +171 -0
  30. package/substrate/.claude/hooks/state-validate.sh +271 -0
  31. package/substrate/.claude/hooks/substrate-clarity-gate.sh +1110 -0
  32. package/substrate/.claude/hooks/temperance-gate.sh +147 -0
  33. package/substrate/.claude/hooks/testing-tier-enforce.sh +233 -0
  34. package/substrate/.claude/hooks/turn-prose-grade-measure.sh +219 -0
  35. package/substrate/.claude/hooks/turn-prose-kiss-check.sh +434 -0
  36. package/substrate/.claude/hooks/vocabulary-migration-check.sh +171 -0
  37. package/substrate/.claude/hooks/whereami-utc-gate.sh +142 -0
  38. package/substrate/.claude/luminaries/alan-cooper.md +170 -0
  39. package/substrate/.claude/luminaries/alistair-cockburn.md +140 -0
  40. package/substrate/.claude/luminaries/amazon-pr-faq.md +34 -0
  41. package/substrate/.claude/luminaries/ash-maurya.md +121 -0
  42. package/substrate/.claude/luminaries/bill-buxton.md +210 -0
  43. package/substrate/.claude/luminaries/charles-sanders-peirce.md +150 -0
  44. package/substrate/.claude/luminaries/david-ogilvy.md +192 -0
  45. package/substrate/.claude/luminaries/don-norman.md +173 -0
  46. package/substrate/.claude/luminaries/edward-tufte.md +179 -0
  47. package/substrate/.claude/luminaries/eric-evans.md +160 -0
  48. package/substrate/.claude/luminaries/frederick-brooks.md +50 -0
  49. package/substrate/.claude/luminaries/gang-of-four.md +157 -0
  50. package/substrate/.claude/luminaries/jason-fried-dhh.md +46 -0
  51. package/substrate/.claude/luminaries/jesse-james-garrett.md +154 -0
  52. package/substrate/.claude/luminaries/john-ousterhout.md +94 -0
  53. package/substrate/.claude/luminaries/karl-popper.md +132 -0
  54. package/substrate/.claude/luminaries/kent-beck.md +168 -0
  55. package/substrate/.claude/luminaries/linus-torvalds.md +218 -0
  56. package/substrate/.claude/luminaries/martin-fowler.md +164 -0
  57. package/substrate/.claude/luminaries/michael-feathers.md +125 -0
  58. package/substrate/.claude/luminaries/michael-nygard.md +118 -0
  59. package/substrate/.claude/luminaries/robert-c-martin.md +164 -0
  60. package/substrate/.claude/luminaries/saltzer-schroeder.md +194 -0
  61. package/substrate/.claude/luminaries/sophia-prater.md +193 -0
  62. package/substrate/.claude/luminaries/stephen-toulmin.md +131 -0
  63. package/substrate/.claude/rules/artifact-ingestion.md +179 -0
  64. package/substrate/.claude/rules/assert-only-after-verify.md +137 -0
  65. package/substrate/.claude/rules/blocked-items.md +146 -0
  66. package/substrate/.claude/rules/branching.md +28 -0
  67. package/substrate/.claude/rules/commit-conventions.md +22 -0
  68. package/substrate/.claude/rules/context-engineering.md +202 -0
  69. package/substrate/.claude/rules/context-management.md +85 -0
  70. package/substrate/.claude/rules/destructive-operations.md +69 -0
  71. package/substrate/.claude/rules/diagnosis.md +38 -0
  72. package/substrate/.claude/rules/guardrails.md +73 -0
  73. package/substrate/.claude/rules/identifier-leak-prevention.md +104 -0
  74. package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +98 -0
  75. package/substrate/.claude/rules/oo-ad-entry-point.md +117 -0
  76. package/substrate/.claude/rules/operator-facing-prose.md +196 -0
  77. package/substrate/.claude/rules/plain-english-discipline.md +154 -0
  78. package/substrate/.claude/rules/pr-body-shape.md +317 -0
  79. package/substrate/.claude/rules/pr-strategy.md +167 -0
  80. package/substrate/.claude/rules/sdlc-gates.md +149 -0
  81. package/substrate/.claude/rules/session-artifacts.md +236 -0
  82. package/substrate/.claude/rules/state-schema-validation.md +162 -0
  83. package/substrate/.claude/rules/whereami-load-bearing.md +202 -0
  84. package/substrate/.claude/rules/writing-craft-discipline.md +92 -0
  85. package/substrate/.claude/skills/build/SKILL.md +640 -0
  86. package/substrate/.claude/skills/decompose/SKILL.md +280 -0
  87. package/substrate/.claude/skills/diagnose/SKILL.md +297 -0
  88. package/substrate/.claude/skills/howdoi/SKILL.md +105 -0
  89. package/substrate/.claude/skills/ia-model/SKILL.md +108 -0
  90. package/substrate/.claude/skills/interaction-design/SKILL.md +112 -0
  91. package/substrate/.claude/skills/interpret-input/SKILL.md +180 -0
  92. package/substrate/.claude/skills/kiss/SKILL.md +449 -0
  93. package/substrate/.claude/skills/launch/SKILL.md +924 -0
  94. package/substrate/.claude/skills/lean-canvas/SKILL.md +332 -0
  95. package/substrate/.claude/skills/longrun/SKILL.md +426 -0
  96. package/substrate/.claude/skills/luminary/SKILL.md +481 -0
  97. package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +177 -0
  98. package/substrate/.claude/skills/onboard-repo/SKILL.md +2190 -0
  99. package/substrate/.claude/skills/pattern-review/SKILL.md +99 -0
  100. package/substrate/.claude/skills/personas/SKILL.md +207 -0
  101. package/substrate/.claude/skills/promote/SKILL.md +283 -0
  102. package/substrate/.claude/skills/requirement/SKILL.md +98 -0
  103. package/substrate/.claude/skills/retro/SKILL.md +117 -0
  104. package/substrate/.claude/skills/riff/SKILL.md +114 -0
  105. package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +163 -0
  106. package/substrate/.claude/skills/session-end/SKILL.md +309 -0
  107. package/substrate/.claude/skills/session-log/SKILL.md +299 -0
  108. package/substrate/.claude/skills/skills/SKILL.md +228 -0
  109. package/substrate/.claude/skills/spec/SKILL.md +105 -0
  110. package/substrate/.claude/skills/sprint/SKILL.md +392 -0
  111. package/substrate/.claude/skills/stage/SKILL.md +384 -0
  112. package/substrate/.claude/skills/state-a-problem/SKILL.md +185 -0
  113. package/substrate/.claude/skills/temperance/SKILL.md +108 -0
  114. package/substrate/.claude/skills/use-case/SKILL.md +417 -0
  115. package/substrate/.claude/skills/user-stories/SKILL.md +268 -0
  116. package/substrate/.claude/skills/value-prop/SKILL.md +251 -0
  117. package/substrate/.claude/skills/verify/SKILL.md +160 -0
  118. package/substrate/.claude/skills/whereami/SKILL.md +307 -0
  119. package/substrate/AGENTS.md +79 -0
  120. package/substrate/CLAUDE-lite.md +85 -0
  121. package/substrate/CODE_OF_CONDUCT.md +28 -0
  122. package/substrate/CONTRIBUTING.md +177 -0
  123. package/substrate/README.md +173 -0
  124. package/substrate/SECURITY.md +19 -0
  125. package/substrate/architecture/decisions/ADR-029-release-pipeline.md +79 -0
  126. package/substrate/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +139 -0
  127. package/substrate/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +192 -0
  128. package/substrate/architecture/decisions/ADR-039-release-tagging-scheme.md +145 -0
  129. package/substrate/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +155 -0
  130. package/substrate/architecture/decisions/ADR-044-unified-skill-body-template.md +162 -0
  131. package/substrate/lib/clean-artifacts-sweep.sh +112 -0
  132. package/substrate/lib/code-comment-discipline.sh +144 -0
  133. package/substrate/lib/composer-preflight.sh +459 -0
  134. package/substrate/lib/hook-inject.sh +255 -0
  135. package/substrate/lib/luminary-pick.sh +96 -0
  136. package/substrate/lib/output-discipline.sh +143 -0
  137. package/substrate/lib/rewrite-check.sh +214 -0
  138. package/substrate/lib/state.sh +1372 -0
  139. package/substrate/lib/telemetry.sh +205 -0
  140. package/substrate/lib/tier-check.sh +138 -0
  141. package/substrate/lib/tier-dependency-audit.sh +933 -0
  142. package/substrate/presence/install/bassclef-hook-connect.sh +178 -0
  143. package/substrate/presence/install/bassclef-sync.dispatcher.template.sh +841 -0
  144. package/substrate/presence/install/bassclef-sync.template.sh +2076 -0
  145. package/substrate/presence/install/schedule-auto-save.cron.sh +88 -0
  146. package/substrate/presence/install/schedule-auto-save.taskscheduler.md +122 -0
  147. package/substrate/scripts/aggregate-telemetry.sh +217 -0
  148. package/substrate/scripts/analyze-tier-dependencies.sh +239 -0
  149. package/substrate/scripts/generate-lite-manifest.sh +489 -0
  150. package/substrate/scripts/generate-tier-manifest.sh +28 -0
  151. package/substrate/scripts/intent-drift-check.sh +456 -0
  152. package/substrate/scripts/lite-manifest-drift-check.sh +146 -0
  153. package/substrate/scripts/render-lite-manifest-doc.sh +150 -0
  154. package/substrate/standards/bassclef-configs-schema.md +232 -0
  155. package/substrate/standards/bassclef-evolution.md +143 -0
  156. package/substrate/standards/bassclef-internal-jargon.md +244 -0
  157. package/substrate/standards/bassclef-managed-sentinel.md +96 -0
  158. package/substrate/standards/bassclef-source-config.md +228 -0
  159. package/substrate/standards/deferred-actions-schema.md +204 -0
  160. package/substrate/standards/docs-sync-allowlist.md +76 -0
  161. package/substrate/standards/graceful-exit.md +227 -0
  162. package/substrate/standards/hook-idempotency.md +102 -0
  163. package/substrate/standards/lite-manifest-schema-changes.md +75 -0
  164. package/substrate/standards/luminary-problem-patterns.md +481 -0
  165. package/substrate/standards/ogilvy-writing-rules.md +225 -0
  166. package/substrate/standards/opener-discipline.md +96 -0
  167. package/substrate/standards/operator-facing-prose-discipline.md +201 -0
  168. package/substrate/standards/project-directory-layout.md +276 -0
  169. package/substrate/standards/release-tagging.md +137 -0
  170. package/substrate/standards/sdlc-compliance.md +286 -0
  171. package/substrate/standards/secrets-lifecycle.md +210 -0
  172. package/substrate/standards/security-scanner-adapter.md +145 -0
  173. package/substrate/standards/skill-output-discipline.md +90 -0
  174. package/substrate/standards/state-spine.md +511 -0
  175. package/substrate/standards/tech-stack-config.md +109 -0
  176. package/substrate/standards/tier-dependency-analysis.md +167 -0
  177. package/substrate/standards/tier-runtime-deps/lite.md +57 -0
  178. package/substrate/standards/tier-tag-schema.md +155 -0
  179. package/substrate/standards/whereami-schema.md +301 -0
  180. package/substrate/standards/writing-guide.md +213 -0
  181. package/substrate/templates/deferred-action-template.md +45 -0
  182. package/substrate/templates/whereami-template.md +101 -0
@@ -0,0 +1,489 @@
1
+ #!/usr/bin/env bash
2
+ # tier: lite
3
+ # Generate lite-manifest.json at repo root.
4
+ #
5
+ # Reads tier: lite frontmatter across the 7 substrate surfaces and emits
6
+ # the manifest per standards/lite-manifest.schema.json v1.0.0.
7
+ #
8
+ # Per bassclef-upstream#1020 (partner packaging manifest) + #1030 (root
9
+ # location + generator). Session 2026-08-01d option b — standalone
10
+ # generator; release-script integration deferred per bet doc Out of scope.
11
+ #
12
+ # Cures per pre-mortem risk ledger docs/risk-ledgers/2026-08-01c-lite-manifest.md:
13
+ # F-b.H1 — resolves repo root via git rev-parse; writes to ${ROOT}/lite-manifest.json
14
+ # F1.1 — real substrate paths (not synthetic); tests iterate all project surfaces
15
+ # F1.3 — iterates ALL 7 surfaces (skills + rules + hooks + luminaries + agents + standards + ADRs)
16
+ # F2.1/2/6/7 — schema validates output at CI drift-check (Step 5)
17
+ #
18
+ # Usage:
19
+ # scripts/generate-lite-manifest.sh # writes lite-manifest.json at repo root
20
+ # scripts/generate-lite-manifest.sh --dry-run # prints JSON to stdout; no file write
21
+ # scripts/generate-lite-manifest.sh --output PATH # writes to specified path (test harness)
22
+ # scripts/generate-lite-manifest.sh --root PATH # override repo root (test harness)
23
+ #
24
+ # Exit codes:
25
+ # 0 — manifest written or dry-run printed
26
+ # 1 — invalid arg or missing dependency (jq, git, shasum/sha256sum)
27
+ # 2 — no lite entries found (schema requires minItems: 1)
28
+
29
+ set -euo pipefail
30
+
31
+ MANIFEST_VERSION="1.5.1"
32
+
33
+ # --- arg parse ---
34
+ DRY_RUN=0
35
+ OUTPUT_PATH=""
36
+ REPO_ROOT_OVERRIDE=""
37
+ TARGET_TIER="lite" # per #1295 — script now tier-parameterizable; default preserves prior API
38
+
39
+ while [[ $# -gt 0 ]]; do
40
+ case "$1" in
41
+ --dry-run) DRY_RUN=1; shift ;;
42
+ --output) OUTPUT_PATH="${2:-}"; shift 2 ;;
43
+ --root) REPO_ROOT_OVERRIDE="${2:-}"; shift 2 ;;
44
+ --tier) TARGET_TIER="${2:-}"; shift 2 ;;
45
+ -h|--help)
46
+ grep -E '^# ' "$0" | sed 's/^# \?//'
47
+ exit 0
48
+ ;;
49
+ *) echo "Unknown arg: $1 (use --help)" >&2; exit 1 ;;
50
+ esac
51
+ done
52
+
53
+ # --- validate tier arg per ADR-043 D1 ---
54
+ case "$TARGET_TIER" in
55
+ lite|standard|ultra|standard-pro) ;;
56
+ *) echo "generate-tier-manifest: invalid --tier '$TARGET_TIER' (allowed: lite, standard, ultra, standard-pro)" >&2; exit 1 ;;
57
+ esac
58
+
59
+ # --- resolve repo root ---
60
+ if [[ -n "$REPO_ROOT_OVERRIDE" ]]; then
61
+ REPO_ROOT="$REPO_ROOT_OVERRIDE"
62
+ else
63
+ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
64
+ fi
65
+
66
+ if [[ -z "$REPO_ROOT" || ! -d "$REPO_ROOT" ]]; then
67
+ echo "generate-lite-manifest: cannot resolve repo root (not in a git tree; use --root)" >&2
68
+ exit 1
69
+ fi
70
+
71
+ # --- dependency check ---
72
+ for cmd in jq git; do
73
+ if ! command -v "$cmd" >/dev/null 2>&1; then
74
+ echo "generate-lite-manifest: missing dependency: $cmd" >&2
75
+ exit 1
76
+ fi
77
+ done
78
+
79
+ if command -v shasum >/dev/null 2>&1; then
80
+ SHA_CMD="shasum -a 256"
81
+ elif command -v sha256sum >/dev/null 2>&1; then
82
+ SHA_CMD="sha256sum"
83
+ else
84
+ echo "generate-lite-manifest: missing dependency: shasum or sha256sum" >&2
85
+ exit 1
86
+ fi
87
+
88
+ # --- default output path (root of the resolved repo; per-tier filename) ---
89
+ if [[ -z "$OUTPUT_PATH" ]]; then
90
+ OUTPUT_PATH="${REPO_ROOT}/${TARGET_TIER}-manifest.json"
91
+ fi
92
+
93
+ # --- generation metadata ---
94
+ GENERATED_AT="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
95
+ UPSTREAM_COMMIT="$(cd "$REPO_ROOT" && git rev-parse HEAD 2>/dev/null || echo '0000000000000000000000000000000000000000')"
96
+
97
+ # --- extractors ---
98
+
99
+ # Extract tier from markdown YAML frontmatter (skills, rules, luminaries, agents, standards, ADRs).
100
+ extract_yaml_tier() {
101
+ awk '
102
+ /^---$/ { c++; if (c == 2) exit; next }
103
+ c == 1 && /^tier:[[:space:]]/ {
104
+ sub(/^tier:[[:space:]]*/, "")
105
+ gsub(/[[:space:]]/, "")
106
+ print
107
+ exit
108
+ }
109
+ ' "$1"
110
+ }
111
+
112
+ # Extract tier from bash hook file # tier: header.
113
+ extract_hook_tier() {
114
+ grep -m1 -E '^#[[:space:]]*tier:[[:space:]]' "$1" 2>/dev/null \
115
+ | sed -E 's/^#[[:space:]]*tier:[[:space:]]*//' \
116
+ | sed -E 's/[[:space:]]*$//' \
117
+ || true
118
+ }
119
+
120
+ # Extract description from markdown YAML frontmatter (first line of description: field).
121
+ extract_yaml_description() {
122
+ awk '
123
+ /^---$/ { c++; if (c == 2) exit; next }
124
+ c == 1 && /^description:[[:space:]]/ {
125
+ sub(/^description:[[:space:]]*/, "")
126
+ sub(/^"/, "")
127
+ sub(/"$/, "")
128
+ sub(/^\047/, "")
129
+ sub(/\047$/, "")
130
+ print
131
+ exit
132
+ }
133
+ ' "$1"
134
+ }
135
+
136
+ # Extract a `<field>:` inline YAML list from the frontmatter as a JSON array string.
137
+ # Handles shape `<field>: [foo, bar]` — bassclef's convention. Returns `[]` when absent or malformed.
138
+ _extract_yaml_inline_list() {
139
+ local file="$1" field="$2" raw
140
+ raw=$(awk -v f="$field" '
141
+ /^---$/ { c++; if (c == 2) exit; next }
142
+ c == 1 && $0 ~ ("^" f ":[[:space:]]*\\[") {
143
+ sub("^" f ":[[:space:]]*", "")
144
+ print
145
+ exit
146
+ }
147
+ ' "$file" 2>/dev/null)
148
+ if [[ -z "$raw" ]]; then
149
+ echo "[]"
150
+ return
151
+ fi
152
+ # Strip enclosing brackets, split on comma, trim, quote each, join. Always output valid JSON.
153
+ echo "$raw" | jq -Rc '
154
+ ltrimstr("[") | rtrimstr("]")
155
+ | split(",")
156
+ | map(sub("^\\s+"; "") | sub("\\s+$"; ""))
157
+ | map(select(length > 0))
158
+ ' 2>/dev/null || echo "[]"
159
+ }
160
+
161
+ extract_yaml_composes_with() {
162
+ _extract_yaml_inline_list "$1" "composes_with"
163
+ }
164
+
165
+ extract_yaml_depends_on() {
166
+ _extract_yaml_inline_list "$1" "depends_on"
167
+ }
168
+
169
+ # Per bassclef-web#268 — inputs + outputs read as inline YAML lists from
170
+ # frontmatter. Stage 1 = frontmatter-declared (deterministic). Stage 2 =
171
+ # body-section extraction (deferred per L169 awk-portability note).
172
+ extract_yaml_inputs() {
173
+ _extract_yaml_inline_list "$1" "inputs"
174
+ }
175
+
176
+ extract_yaml_outputs() {
177
+ _extract_yaml_inline_list "$1" "outputs"
178
+ }
179
+
180
+ # Extract a `<field>:` YAML string value from the frontmatter. Handles inline
181
+ # form `<field>: some text`. Multi-line block scalars (`|` / `>`) are not
182
+ # supported today — Feathers F3 single-line contract per goal 2026-09-07c.
183
+ # Returns empty string when the field is absent, quoting normalized like
184
+ # extract_yaml_description does.
185
+ _extract_yaml_string_field() {
186
+ awk -v f="$2" '
187
+ /^---$/ { c++; if (c == 2) exit; next }
188
+ c == 1 && $0 ~ ("^" f ":[[:space:]]") {
189
+ sub("^" f ":[[:space:]]*", "")
190
+ sub(/^"/, "")
191
+ sub(/"$/, "")
192
+ sub(/^\047/, "")
193
+ sub(/\047$/, "")
194
+ print
195
+ exit
196
+ }
197
+ ' "$1"
198
+ }
199
+
200
+ # Extract `problem:` frontmatter field per bassclef-web#268 + web#265 Stage 1
201
+ # (frontmatter-first path per Peirce disposition c on bassclef-upstream#1533).
202
+ # Skill-surface-only per Hoare H5 pre-mortem. Empty when absent — jq guard
203
+ # drops the key.
204
+ extract_yaml_problem() {
205
+ _extract_yaml_string_field "$1" "problem"
206
+ }
207
+
208
+ # Extract `value:` frontmatter field per bassclef-web#268 + web#265 Stage 1.
209
+ # Skill-surface-only per Hoare H5 pre-mortem. Empty when absent.
210
+ extract_yaml_value() {
211
+ _extract_yaml_string_field "$1" "value"
212
+ }
213
+
214
+ # Body-anchor extraction for problem + value deferred per bassclef-web#265
215
+ # Stage 2 note. Stage 1 awk section extraction proved non-deterministic
216
+ # across BSD (macOS) and GNU (Linux) awk implementations. Schema fields
217
+ # remain defined for Stage 2 hand-authored `data/skill-pitches.json`
218
+ # overrides. Frontmatter path above ships today (goal 2026-09-07c Step 3).
219
+ # See PR discussion on bassclef-upstream#1480.
220
+
221
+ # Extract description from bash hook file — first non-shebang, non-tier, non-metadata comment.
222
+ extract_hook_description() {
223
+ grep -E '^#' "$1" 2>/dev/null \
224
+ | grep -vE '^#!' \
225
+ | grep -vE '^#[[:space:]]*(tier|install-class|matcher|event|luminary|@)' \
226
+ | grep -vE '^#[[:space:]]*$' \
227
+ | head -1 \
228
+ | sed -E 's/^#[[:space:]]*//' \
229
+ | sed -E 's/[[:space:]]*$//' \
230
+ || true
231
+ }
232
+
233
+ sha256_file() {
234
+ $SHA_CMD "$1" | awk '{print "sha256:"$1}'
235
+ }
236
+
237
+ # --- emit entries for a single surface ---
238
+ # Args:
239
+ # $1 = surface type ("skill", "rule", etc.)
240
+ # $2 = tier extractor function name
241
+ # $3 = description extractor function name
242
+ # $4 = slug source ("dirname" | "basename" | "adr")
243
+ # $5+ = file paths (already expanded)
244
+ emit_entries() {
245
+ local surface_type="$1"; shift
246
+ local tier_fn="$1"; shift
247
+ local desc_fn="$1"; shift
248
+ local slug_from="$1"; shift
249
+
250
+ local f slug tier path hash desc
251
+ # Per #1295 — for standard/ultra manifests, ships derives as SUPERSET of
252
+ # lite. So standard includes {lite, standard}; ultra includes {lite, standard, ultra}.
253
+ # Adopters at a given tier see everything their tier plus lower tiers ship.
254
+ local include_lite=0 include_standard=0 include_ultra=0
255
+ case "$TARGET_TIER" in
256
+ lite) include_lite=1 ;;
257
+ standard) include_lite=1; include_standard=1 ;;
258
+ standard-pro) include_lite=1; include_standard=1 ;;
259
+ ultra) include_lite=1; include_standard=1; include_ultra=1 ;;
260
+ esac
261
+ for f in "$@"; do
262
+ [[ -f "$f" ]] || continue
263
+ # Skip TEMPLATE + Index files — scaffolding not real substrate;
264
+ # they carry uppercase slugs that violate schema pattern.
265
+ case "$(basename "$f")" in
266
+ TEMPLATE.md|ADR-Index.md) continue ;;
267
+ esac
268
+ tier=$("$tier_fn" "$f" || true)
269
+ case "$tier" in
270
+ lite) [[ "$include_lite" == "1" ]] || continue ;;
271
+ standard) [[ "$include_standard" == "1" ]] || continue ;;
272
+ standard-pro) [[ "$include_standard" == "1" ]] || continue ;;
273
+ ultra) [[ "$include_ultra" == "1" ]] || continue ;;
274
+ *) continue ;;
275
+ esac
276
+
277
+ case "$slug_from" in
278
+ dirname)
279
+ slug=$(basename "$(dirname "$f")")
280
+ ;;
281
+ adr)
282
+ slug=$(basename "$f" .md | sed -E 's/^ADR-//')
283
+ ;;
284
+ *)
285
+ slug=$(basename "$f")
286
+ slug="${slug%.md}"
287
+ slug="${slug%.sh}"
288
+ slug="${slug%.json}" # #1295 embedding entries
289
+ # Lowercase + normalize (schema pattern: ^[a-z0-9][a-z0-9-]*[a-z0-9]$)
290
+ slug=$(echo "$slug" | tr '[:upper:]' '[:lower:]' | sed -E 's/^ADR-//i' | sed -E 's/[^a-z0-9-]/-/g' | sed -E 's/^-+//;s/-+$//;s/-+/-/g')
291
+ ;;
292
+ esac
293
+
294
+ path="${f#$REPO_ROOT/}"
295
+ hash=$(sha256_file "$f")
296
+ desc=$("$desc_fn" "$f" || true)
297
+
298
+ # Extract additive graph fields per bassclef-web#104 partial.
299
+ # composes_with + depends_on read from YAML frontmatter via jq (deterministic).
300
+ # Every markdown surface with frontmatter carries these.
301
+ local composes_with_json="[]"
302
+ local depends_on_json="[]"
303
+ case "$surface_type" in
304
+ skill|rule|luminary|agent|standard|adr|template|root-doc)
305
+ composes_with_json=$(extract_yaml_composes_with "$f" 2>/dev/null || echo "[]")
306
+ depends_on_json=$(extract_yaml_depends_on "$f" 2>/dev/null || echo "[]")
307
+ ;;
308
+ esac
309
+
310
+ # inputs + outputs + problem + value are skill-surface-only per Hoare H5
311
+ # pre-mortem (docs/risk-ledgers/2026-09-07c-lite-manifest-schema-extractor-
312
+ # backfill-ledger.md). Other surfaces (rules, luminaries, etc) do not
313
+ # semantically carry "what to feed" / "what comes back" — they are steering,
314
+ # not tool-like. Per goal 2026-09-07c Step 3.
315
+ local inputs_json="[]"
316
+ local outputs_json="[]"
317
+ local problem=""
318
+ local value=""
319
+ if [ "$surface_type" = "skill" ]; then
320
+ inputs_json=$(extract_yaml_inputs "$f" 2>/dev/null || echo "[]")
321
+ outputs_json=$(extract_yaml_outputs "$f" 2>/dev/null || echo "[]")
322
+ problem=$(extract_yaml_problem "$f" 2>/dev/null || true)
323
+ value=$(extract_yaml_value "$f" 2>/dev/null || true)
324
+ fi
325
+
326
+ jq -c -n \
327
+ --arg slug "$slug" \
328
+ --arg type "$surface_type" \
329
+ --arg path "$path" \
330
+ --arg tier "$tier" \
331
+ --arg hash "$hash" \
332
+ --arg desc "${desc:-}" \
333
+ --arg problem "${problem:-}" \
334
+ --arg value "${value:-}" \
335
+ --argjson composes_with "${composes_with_json:-[]}" \
336
+ --argjson depends_on "${depends_on_json:-[]}" \
337
+ --argjson inputs "${inputs_json:-[]}" \
338
+ --argjson outputs "${outputs_json:-[]}" \
339
+ '{slug:$slug, type:$type, path:$path, tier:$tier, content_hash:$hash}
340
+ + (if $desc == "" then {} else {description:$desc} end)
341
+ + (if ($composes_with | length) == 0 then {} else {composes_with:$composes_with} end)
342
+ + (if ($depends_on | length) == 0 then {} else {depends_on:$depends_on} end)
343
+ + (if ($inputs | length) == 0 then {} else {inputs:$inputs} end)
344
+ + (if ($outputs | length) == 0 then {} else {outputs:$outputs} end)
345
+ + (if $problem == "" then {} else {problem:$problem} end)
346
+ + (if $value == "" then {} else {value:$value} end)'
347
+ done
348
+ }
349
+
350
+ # --- collect entries from 13 surfaces per #1392 Shape 3 (goal 2026-08-27a) ---
351
+ # Original 8 (7 doc + 1 embedding per #1295 Step 5) plus 5 new install surfaces:
352
+ # lib (lib/*.sh) + script (scripts/*.sh) + presence-template (presence/install/*)
353
+ # + template (templates/*.md) + root-doc (root-level *.md)
354
+ # The extension makes the manifest the definitive install list for bassclef-cli.
355
+ # Note: `readarray` is bash 4.0+; macOS ships bash 3.2. Use while-read loop.
356
+ STANDARDS_FILES=()
357
+ while IFS= read -r f; do
358
+ STANDARDS_FILES+=("$f")
359
+ done < <(find "$REPO_ROOT/standards" -type f -name '*.md' | sort)
360
+
361
+ # Embedding files (JSON) — per #1295 Step 5; ultra tier ships Voyage vectors
362
+ EMBEDDING_FILES=()
363
+ while IFS= read -r f; do
364
+ EMBEDDING_FILES+=("$f")
365
+ done < <(find "$REPO_ROOT/.claude/embeddings" -type f -name '*.json' 2>/dev/null | sort)
366
+
367
+ # Lib files (bash) — per #1392 Shape 3; adopter runtime needs lib/state.sh + lib/hook-inject.sh etc
368
+ LIB_FILES=()
369
+ while IFS= read -r f; do
370
+ LIB_FILES+=("$f")
371
+ done < <(find "$REPO_ROOT/lib" -maxdepth 1 -type f -name '*.sh' 2>/dev/null | sort)
372
+
373
+ # Script files (bash) — per #1392 Shape 3; adopter runtime needs scripts/bassclef-*.sh helpers
374
+ SCRIPT_FILES=()
375
+ while IFS= read -r f; do
376
+ SCRIPT_FILES+=("$f")
377
+ done < <(find "$REPO_ROOT/scripts" -maxdepth 1 -type f -name '*.sh' 2>/dev/null | sort)
378
+
379
+ # Presence templates (bash + md) — per #1392 Shape 3; adopter install dispatches through these
380
+ PRESENCE_TEMPLATE_SH_FILES=()
381
+ while IFS= read -r f; do
382
+ PRESENCE_TEMPLATE_SH_FILES+=("$f")
383
+ done < <(find "$REPO_ROOT/presence/install" -maxdepth 1 -type f -name '*.sh' 2>/dev/null | sort)
384
+
385
+ PRESENCE_TEMPLATE_MD_FILES=()
386
+ while IFS= read -r f; do
387
+ PRESENCE_TEMPLATE_MD_FILES+=("$f")
388
+ done < <(find "$REPO_ROOT/presence/install" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort)
389
+
390
+ # Templates (md) — per #1392 Shape 3; chronicle-template + iteration-goal etc adopters copy
391
+ TEMPLATE_FILES=()
392
+ while IFS= read -r f; do
393
+ TEMPLATE_FILES+=("$f")
394
+ done < <(find "$REPO_ROOT/templates" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort)
395
+
396
+ # Root docs (md) — per #1392 Shape 3; README + CLAUDE + AGENTS adopters read on install
397
+ ROOT_DOC_FILES=()
398
+ while IFS= read -r f; do
399
+ ROOT_DOC_FILES+=("$f")
400
+ done < <(find "$REPO_ROOT" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort)
401
+
402
+ # Extract tier from JSON root-key `"tier"` or `"_tier"` — per #1295
403
+ extract_json_tier() {
404
+ head -5 "$1" 2>/dev/null | awk '
405
+ /"tier"[[:space:]]*:[[:space:]]*"/ {
406
+ match($0, /"tier"[[:space:]]*:[[:space:]]*"[^"]+"/)
407
+ v=substr($0, RSTART, RLENGTH)
408
+ sub(/^"tier"[[:space:]]*:[[:space:]]*"/,"",v); sub(/"$/,"",v)
409
+ print v; exit
410
+ }
411
+ /"_tier"[[:space:]]*:[[:space:]]*"/ {
412
+ match($0, /"_tier"[[:space:]]*:[[:space:]]*"[^"]+"/)
413
+ v=substr($0, RSTART, RLENGTH)
414
+ sub(/^"_tier"[[:space:]]*:[[:space:]]*"/,"",v); sub(/"$/,"",v)
415
+ print v; exit
416
+ }'
417
+ }
418
+
419
+ # Embeddings have no description field; return empty
420
+ extract_json_description() {
421
+ echo ""
422
+ }
423
+
424
+ ENTRIES_JSON=$(
425
+ {
426
+ emit_entries "skill" extract_yaml_tier extract_yaml_description dirname "$REPO_ROOT/.claude/skills/"*/SKILL.md
427
+ emit_entries "rule" extract_yaml_tier extract_yaml_description basename "$REPO_ROOT/.claude/rules/"*.md
428
+ emit_entries "hook" extract_hook_tier extract_hook_description basename "$REPO_ROOT/.claude/hooks/"*.sh
429
+ emit_entries "luminary" extract_yaml_tier extract_yaml_description basename "$REPO_ROOT/.claude/luminaries/"*.md
430
+ emit_entries "agent" extract_yaml_tier extract_yaml_description basename "$REPO_ROOT/.claude/agents/"*.md
431
+ emit_entries "standard" extract_yaml_tier extract_yaml_description basename "${STANDARDS_FILES[@]}"
432
+ emit_entries "adr" extract_yaml_tier extract_yaml_description adr "$REPO_ROOT/architecture/decisions/"ADR-*.md
433
+ if [[ ${#EMBEDDING_FILES[@]} -gt 0 ]]; then
434
+ emit_entries "embedding" extract_json_tier extract_json_description basename "${EMBEDDING_FILES[@]}"
435
+ fi
436
+ # Per #1392 Shape 3 — 5 new install surfaces for bassclef-cli
437
+ if [[ ${#LIB_FILES[@]} -gt 0 ]]; then
438
+ emit_entries "lib" extract_hook_tier extract_hook_description basename "${LIB_FILES[@]}"
439
+ fi
440
+ if [[ ${#SCRIPT_FILES[@]} -gt 0 ]]; then
441
+ emit_entries "script" extract_hook_tier extract_hook_description basename "${SCRIPT_FILES[@]}"
442
+ fi
443
+ if [[ ${#PRESENCE_TEMPLATE_SH_FILES[@]} -gt 0 ]]; then
444
+ emit_entries "presence-template" extract_hook_tier extract_hook_description basename "${PRESENCE_TEMPLATE_SH_FILES[@]}"
445
+ fi
446
+ if [[ ${#PRESENCE_TEMPLATE_MD_FILES[@]} -gt 0 ]]; then
447
+ emit_entries "presence-template" extract_yaml_tier extract_yaml_description basename "${PRESENCE_TEMPLATE_MD_FILES[@]}"
448
+ fi
449
+ if [[ ${#TEMPLATE_FILES[@]} -gt 0 ]]; then
450
+ emit_entries "template" extract_yaml_tier extract_yaml_description basename "${TEMPLATE_FILES[@]}"
451
+ fi
452
+ if [[ ${#ROOT_DOC_FILES[@]} -gt 0 ]]; then
453
+ emit_entries "root-doc" extract_yaml_tier extract_yaml_description basename "${ROOT_DOC_FILES[@]}"
454
+ fi
455
+ } | jq -s 'sort_by(.type, .slug)'
456
+ )
457
+
458
+ ENTRY_COUNT=$(echo "$ENTRIES_JSON" | jq 'length')
459
+
460
+ if [[ "$ENTRY_COUNT" -lt 1 ]]; then
461
+ echo "generate-tier-manifest: no entries found for tier '$TARGET_TIER' (schema requires minItems: 1)" >&2
462
+ exit 2
463
+ fi
464
+
465
+ # --- assemble manifest ---
466
+ # Includes tier root-key per #1295 — the manifest itself carries its own tier tag
467
+ # so tier-tag-required-at-write.sh recognizes it. Per Saltzer-Schroeder complete
468
+ # mediation — no derived artifact escapes the tier system.
469
+ MANIFEST_JSON=$(jq -n \
470
+ --arg tier "$TARGET_TIER" \
471
+ --arg mv "$MANIFEST_VERSION" \
472
+ --arg ga "$GENERATED_AT" \
473
+ --argjson entries "$ENTRIES_JSON" \
474
+ '{tier:$tier, manifest_version:$mv, generated_at:$ga, entries:$entries}')
475
+
476
+ # Per bassclef-upstream#1508 Cure a: upstream_commit dropped from manifest
477
+ # content. Every rebase over a merged sibling PR guaranteed a conflict
478
+ # because the hash changes per parent. Traceability now comes from git
479
+ # log on the manifest file itself. `generated_at` still causes minor
480
+ # timestamp conflicts but is human-scannable; drop deferred if the class
481
+ # still recurs.
482
+
483
+ # --- emit ---
484
+ if [[ "$DRY_RUN" == "1" ]]; then
485
+ echo "$MANIFEST_JSON"
486
+ else
487
+ echo "$MANIFEST_JSON" > "$OUTPUT_PATH"
488
+ echo "Wrote $OUTPUT_PATH ($ENTRY_COUNT entries; commit ${UPSTREAM_COMMIT:0:7})" >&2
489
+ fi
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # tier: lite
3
+ # generate-tier-manifest.sh — thin wrapper over generate-lite-manifest.sh
4
+ # for the tier-agnostic API per bassclef-upstream#1295.
5
+ #
6
+ # generate-lite-manifest.sh keeps its historical name for backward compat.
7
+ # This wrapper exposes the new API: `generate-tier-manifest.sh <tier>`.
8
+ #
9
+ # Usage:
10
+ # bash scripts/generate-tier-manifest.sh lite # writes lite-manifest.json
11
+ # bash scripts/generate-tier-manifest.sh standard # writes standard-manifest.json (superset of lite)
12
+ # bash scripts/generate-tier-manifest.sh ultra # writes ultra-manifest.json (superset of lite + standard)
13
+ # bash scripts/generate-tier-manifest.sh <tier> --dry-run
14
+ #
15
+ # Per #1295 body L23 — standard + ultra manifests derived as supersets of lite.
16
+
17
+ set -euo pipefail
18
+
19
+ if [ $# -lt 1 ]; then
20
+ echo "usage: $0 <tier> [--dry-run] [--output PATH] [--root PATH]" >&2
21
+ echo " tier: lite | standard | ultra | standard-pro" >&2
22
+ exit 1
23
+ fi
24
+
25
+ TIER="$1"; shift
26
+
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ exec bash "${SCRIPT_DIR}/generate-lite-manifest.sh" --tier "$TIER" "$@"