@thebassclef/lite 0.1.2 → 1.0.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 (293) hide show
  1. package/dist/cli.cjs +238 -127
  2. package/dist/cli.js +240 -129
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/lite/.bassclef-source.json +10 -0
  7. package/dist/lite/.claude/settings.json +212 -0
  8. package/dist/lite/CLAUDE.md +41 -0
  9. package/dist/lite/gitignore +58 -0
  10. package/dist/lite/standards/bassclef-wiring-manifest.json +497 -0
  11. package/dist/lite/whereami.md +24 -0
  12. package/package.json +8 -2
  13. package/substrate/.bassclef/lite-manifest.json +0 -2701
  14. package/substrate/.claude/agents/architect.md +0 -70
  15. package/substrate/.claude/agents/builder.md +0 -114
  16. package/substrate/.claude/agents/designer.md +0 -156
  17. package/substrate/.claude/agents/reviewer.md +0 -88
  18. package/substrate/.claude/hooks/artifact-ingestion-gate.sh +0 -357
  19. package/substrate/.claude/hooks/assert-verify-steering.sh +0 -77
  20. package/substrate/.claude/hooks/bassclef-source-config-validate.sh +0 -215
  21. package/substrate/.claude/hooks/bassclef-sync.sh +0 -634
  22. package/substrate/.claude/hooks/compound-noun-scrub.sh +0 -292
  23. package/substrate/.claude/hooks/kiss-expansion-inject.sh +0 -69
  24. package/substrate/.claude/hooks/longrun-prep-compounding-axis-check.sh +0 -492
  25. package/substrate/.claude/hooks/longrun-prep-compounding-sequence-check.sh +0 -492
  26. package/substrate/.claude/hooks/plain-english-steering.sh +0 -156
  27. package/substrate/.claude/hooks/post-skill-friction-check.sh +0 -177
  28. package/substrate/.claude/hooks/post-skill-telemetry.sh +0 -62
  29. package/substrate/.claude/hooks/pre-build-gate.sh +0 -511
  30. package/substrate/.claude/hooks/pre-commit-gate.sh +0 -451
  31. package/substrate/.claude/hooks/session-end.sh +0 -433
  32. package/substrate/.claude/hooks/session-reflection.sh +0 -303
  33. package/substrate/.claude/hooks/skill-body-grade-gate.sh +0 -219
  34. package/substrate/.claude/hooks/skill-body-intent-drift.sh +0 -107
  35. package/substrate/.claude/hooks/skill-step-list-check.sh +0 -171
  36. package/substrate/.claude/hooks/state-validate.sh +0 -271
  37. package/substrate/.claude/hooks/substrate-clarity-gate.sh +0 -1110
  38. package/substrate/.claude/hooks/temperance-gate.sh +0 -147
  39. package/substrate/.claude/hooks/testing-tier-enforce.sh +0 -233
  40. package/substrate/.claude/hooks/turn-prose-grade-measure.sh +0 -219
  41. package/substrate/.claude/hooks/turn-prose-kiss-check.sh +0 -463
  42. package/substrate/.claude/hooks/vocabulary-migration-check.sh +0 -171
  43. package/substrate/.claude/hooks/whereami-utc-gate.sh +0 -142
  44. package/substrate/.claude/luminaries/alan-cooper.md +0 -170
  45. package/substrate/.claude/luminaries/alistair-cockburn.md +0 -140
  46. package/substrate/.claude/luminaries/amazon-pr-faq.md +0 -34
  47. package/substrate/.claude/luminaries/ash-maurya.md +0 -121
  48. package/substrate/.claude/luminaries/bill-buxton.md +0 -210
  49. package/substrate/.claude/luminaries/charles-sanders-peirce.md +0 -150
  50. package/substrate/.claude/luminaries/david-ogilvy.md +0 -192
  51. package/substrate/.claude/luminaries/don-norman.md +0 -173
  52. package/substrate/.claude/luminaries/edward-tufte.md +0 -179
  53. package/substrate/.claude/luminaries/eric-evans.md +0 -160
  54. package/substrate/.claude/luminaries/frederick-brooks.md +0 -50
  55. package/substrate/.claude/luminaries/gang-of-four.md +0 -157
  56. package/substrate/.claude/luminaries/glenford-myers.md +0 -230
  57. package/substrate/.claude/luminaries/hunt-thomas.md +0 -115
  58. package/substrate/.claude/luminaries/hyrum-wright.md +0 -94
  59. package/substrate/.claude/luminaries/jason-fried-dhh.md +0 -46
  60. package/substrate/.claude/luminaries/jesse-james-garrett.md +0 -154
  61. package/substrate/.claude/luminaries/john-ousterhout.md +0 -94
  62. package/substrate/.claude/luminaries/karl-popper.md +0 -132
  63. package/substrate/.claude/luminaries/kent-beck.md +0 -168
  64. package/substrate/.claude/luminaries/linus-torvalds.md +0 -218
  65. package/substrate/.claude/luminaries/martin-fowler.md +0 -164
  66. package/substrate/.claude/luminaries/michael-feathers.md +0 -125
  67. package/substrate/.claude/luminaries/michael-nygard.md +0 -118
  68. package/substrate/.claude/luminaries/robert-c-martin.md +0 -164
  69. package/substrate/.claude/luminaries/saltzer-schroeder.md +0 -194
  70. package/substrate/.claude/luminaries/sophia-prater.md +0 -193
  71. package/substrate/.claude/luminaries/stephen-toulmin.md +0 -131
  72. package/substrate/.claude/luminaries/tony-hoare.md +0 -170
  73. package/substrate/.claude/luminaries/vaughn-vernon.md +0 -50
  74. package/substrate/.claude/luminaries/w-edwards-deming.md +0 -158
  75. package/substrate/.claude/rules/accessor-library-discipline.md +0 -138
  76. package/substrate/.claude/rules/adr-discipline.md +0 -120
  77. package/substrate/.claude/rules/api-conventions.md +0 -125
  78. package/substrate/.claude/rules/artifact-ingestion.md +0 -179
  79. package/substrate/.claude/rules/assert-only-after-verify.md +0 -137
  80. package/substrate/.claude/rules/blocked-items.md +0 -146
  81. package/substrate/.claude/rules/bootstrap-pair-discipline.md +0 -141
  82. package/substrate/.claude/rules/branching.md +0 -28
  83. package/substrate/.claude/rules/cold-adopter-harness-discipline.md +0 -129
  84. package/substrate/.claude/rules/commit-conventions.md +0 -22
  85. package/substrate/.claude/rules/compounding-axis-fresh-analysis.md +0 -188
  86. package/substrate/.claude/rules/compounding-sequence-fresh-analysis.md +0 -188
  87. package/substrate/.claude/rules/context-engineering.md +0 -202
  88. package/substrate/.claude/rules/context-management.md +0 -85
  89. package/substrate/.claude/rules/defensive-bash.md +0 -68
  90. package/substrate/.claude/rules/deferred-actions.md +0 -233
  91. package/substrate/.claude/rules/destructive-operations.md +0 -69
  92. package/substrate/.claude/rules/diagnosis.md +0 -38
  93. package/substrate/.claude/rules/github-issue-flash-tweet.md +0 -156
  94. package/substrate/.claude/rules/guardrails.md +0 -73
  95. package/substrate/.claude/rules/hook-wire-on-author.md +0 -103
  96. package/substrate/.claude/rules/identifier-leak-prevention.md +0 -104
  97. package/substrate/.claude/rules/iteration-bet-brief-completeness.md +0 -54
  98. package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +0 -98
  99. package/substrate/.claude/rules/longrun-prep-plan-doc-compression.md +0 -89
  100. package/substrate/.claude/rules/loop-discipline.md +0 -81
  101. package/substrate/.claude/rules/manual-prod-approval.md +0 -100
  102. package/substrate/.claude/rules/marker-enrichment-discipline.md +0 -99
  103. package/substrate/.claude/rules/mobile-ephemeral-session.md +0 -109
  104. package/substrate/.claude/rules/new-dependency-check.md +0 -51
  105. package/substrate/.claude/rules/oo-ad-entry-point.md +0 -117
  106. package/substrate/.claude/rules/operator-facing-prose.md +0 -196
  107. package/substrate/.claude/rules/option-label-discipline.md +0 -108
  108. package/substrate/.claude/rules/pattern-annotation.md +0 -100
  109. package/substrate/.claude/rules/plain-english-discipline.md +0 -156
  110. package/substrate/.claude/rules/plan-enumeration-needs-value-props.md +0 -211
  111. package/substrate/.claude/rules/pr-body-shape.md +0 -317
  112. package/substrate/.claude/rules/pr-strategy.md +0 -167
  113. package/substrate/.claude/rules/pr-title-shape.md +0 -161
  114. package/substrate/.claude/rules/prototype-workflow.md +0 -65
  115. package/substrate/.claude/rules/reserved-skill-names.md +0 -123
  116. package/substrate/.claude/rules/schema-management.md +0 -49
  117. package/substrate/.claude/rules/sdlc-gates.md +0 -149
  118. package/substrate/.claude/rules/security.md +0 -37
  119. package/substrate/.claude/rules/session-artifacts.md +0 -236
  120. package/substrate/.claude/rules/skill-composition-declarations.md +0 -124
  121. package/substrate/.claude/rules/skill-description-clarity.md +0 -247
  122. package/substrate/.claude/rules/skill-procedure-step-list.md +0 -137
  123. package/substrate/.claude/rules/state-schema-validation.md +0 -162
  124. package/substrate/.claude/rules/stuck-signal-diagnostic.md +0 -140
  125. package/substrate/.claude/rules/substrate-config-schema.md +0 -98
  126. package/substrate/.claude/rules/test-list-discipline.md +0 -175
  127. package/substrate/.claude/rules/test-sufficiency.md +0 -210
  128. package/substrate/.claude/rules/testing-tier-config.md +0 -145
  129. package/substrate/.claude/rules/testing.md +0 -38
  130. package/substrate/.claude/rules/turn-estimate-grounding.md +0 -134
  131. package/substrate/.claude/rules/visual-hierarchy.md +0 -437
  132. package/substrate/.claude/rules/we-dont-break-adopters.md +0 -126
  133. package/substrate/.claude/rules/whereami-load-bearing.md +0 -202
  134. package/substrate/.claude/rules/writing-craft-discipline.md +0 -92
  135. package/substrate/.claude/rules/wu-sequencing-compounds.md +0 -145
  136. package/substrate/.claude/skills/build/SKILL.md +0 -640
  137. package/substrate/.claude/skills/chronicle/SKILL.md +0 -55
  138. package/substrate/.claude/skills/clean-artifacts/SKILL.md +0 -249
  139. package/substrate/.claude/skills/decompose/SKILL.md +0 -280
  140. package/substrate/.claude/skills/diagnose/SKILL.md +0 -297
  141. package/substrate/.claude/skills/feynman/SKILL.md +0 -90
  142. package/substrate/.claude/skills/howdoi/SKILL.md +0 -105
  143. package/substrate/.claude/skills/ia-model/SKILL.md +0 -108
  144. package/substrate/.claude/skills/interaction-design/SKILL.md +0 -112
  145. package/substrate/.claude/skills/interpret-input/SKILL.md +0 -180
  146. package/substrate/.claude/skills/journal/SKILL.md +0 -209
  147. package/substrate/.claude/skills/kiss/SKILL.md +0 -449
  148. package/substrate/.claude/skills/launch/SKILL.md +0 -915
  149. package/substrate/.claude/skills/lean-canvas/SKILL.md +0 -332
  150. package/substrate/.claude/skills/longrun/SKILL.md +0 -463
  151. package/substrate/.claude/skills/luminary/SKILL.md +0 -481
  152. package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +0 -177
  153. package/substrate/.claude/skills/onboard-repo/SKILL.md +0 -1624
  154. package/substrate/.claude/skills/pattern-review/SKILL.md +0 -99
  155. package/substrate/.claude/skills/personas/SKILL.md +0 -207
  156. package/substrate/.claude/skills/promote/SKILL.md +0 -283
  157. package/substrate/.claude/skills/requirement/SKILL.md +0 -98
  158. package/substrate/.claude/skills/retro/SKILL.md +0 -117
  159. package/substrate/.claude/skills/riff/SKILL.md +0 -114
  160. package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +0 -163
  161. package/substrate/.claude/skills/session-end/SKILL.md +0 -309
  162. package/substrate/.claude/skills/session-log/SKILL.md +0 -299
  163. package/substrate/.claude/skills/skills/SKILL.md +0 -228
  164. package/substrate/.claude/skills/spec/SKILL.md +0 -105
  165. package/substrate/.claude/skills/sprint/SKILL.md +0 -392
  166. package/substrate/.claude/skills/stage/SKILL.md +0 -384
  167. package/substrate/.claude/skills/state-a-problem/SKILL.md +0 -185
  168. package/substrate/.claude/skills/temperance/SKILL.md +0 -108
  169. package/substrate/.claude/skills/use-case/SKILL.md +0 -417
  170. package/substrate/.claude/skills/user-stories/SKILL.md +0 -268
  171. package/substrate/.claude/skills/value-prop/SKILL.md +0 -251
  172. package/substrate/.claude/skills/verify/SKILL.md +0 -160
  173. package/substrate/.claude/skills/visual-review/SKILL.md +0 -503
  174. package/substrate/.claude/skills/whats-the-plan/SKILL.md +0 -202
  175. package/substrate/.claude/skills/whereami/SKILL.md +0 -307
  176. package/substrate/AGENTS.md +0 -79
  177. package/substrate/CLAUDE-lite.md +0 -85
  178. package/substrate/CODE_OF_CONDUCT.md +0 -28
  179. package/substrate/CONTRIBUTING.md +0 -177
  180. package/substrate/README.md +0 -173
  181. package/substrate/SECURITY.md +0 -19
  182. package/substrate/architecture/decisions/ADR-029-release-pipeline.md +0 -79
  183. package/substrate/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +0 -139
  184. package/substrate/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +0 -192
  185. package/substrate/architecture/decisions/ADR-039-release-tagging-scheme.md +0 -145
  186. package/substrate/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +0 -155
  187. package/substrate/architecture/decisions/ADR-044-unified-skill-body-template.md +0 -162
  188. package/substrate/lib/clean-artifacts-sweep.sh +0 -112
  189. package/substrate/lib/code-comment-discipline.sh +0 -144
  190. package/substrate/lib/composer-preflight.sh +0 -459
  191. package/substrate/lib/hook-inject.sh +0 -255
  192. package/substrate/lib/luminary-pick.sh +0 -96
  193. package/substrate/lib/output-discipline.sh +0 -143
  194. package/substrate/lib/prose-scan-boundary.sh +0 -171
  195. package/substrate/lib/rewrite-check.sh +0 -214
  196. package/substrate/lib/state.sh +0 -1372
  197. package/substrate/lib/telemetry.sh +0 -205
  198. package/substrate/lib/tier-check.sh +0 -187
  199. package/substrate/lib/tier-dependency-audit.sh +0 -1088
  200. package/substrate/presence/install/bassclef-hook-connect.sh +0 -178
  201. package/substrate/presence/install/bassclef-sync.dispatcher.template.sh +0 -841
  202. package/substrate/presence/install/bassclef-sync.template.sh +0 -2076
  203. package/substrate/presence/install/schedule-auto-save.cron.sh +0 -88
  204. package/substrate/presence/install/schedule-auto-save.taskscheduler.md +0 -122
  205. package/substrate/scripts/aggregate-telemetry.sh +0 -217
  206. package/substrate/scripts/analyze-tier-dependencies.sh +0 -239
  207. package/substrate/scripts/generate-lite-manifest.sh +0 -505
  208. package/substrate/scripts/generate-tier-manifest.sh +0 -28
  209. package/substrate/scripts/intent-drift-check.sh +0 -456
  210. package/substrate/scripts/lite-manifest-drift-check.sh +0 -146
  211. package/substrate/scripts/render-lite-manifest-doc.sh +0 -150
  212. package/substrate/standards/adr-template.md +0 -86
  213. package/substrate/standards/api-conventions/nextjs.md +0 -84
  214. package/substrate/standards/artifact-composition.md +0 -209
  215. package/substrate/standards/bash-hook-safety.md +0 -246
  216. package/substrate/standards/bassclef-configs-schema.md +0 -232
  217. package/substrate/standards/bassclef-evolution.md +0 -143
  218. package/substrate/standards/bassclef-internal-jargon.md +0 -244
  219. package/substrate/standards/bassclef-managed-sentinel.md +0 -96
  220. package/substrate/standards/bassclef-source-config.md +0 -228
  221. package/substrate/standards/branch-stacking.md +0 -408
  222. package/substrate/standards/code-safety-principles.md +0 -176
  223. package/substrate/standards/composer-prerequisites.md +0 -155
  224. package/substrate/standards/deferred-actions-schema.md +0 -204
  225. package/substrate/standards/dependency-discipline/cargo.md +0 -39
  226. package/substrate/standards/dependency-discipline/gem.md +0 -43
  227. package/substrate/standards/dependency-discipline/go-mod.md +0 -41
  228. package/substrate/standards/dependency-discipline/npm.md +0 -42
  229. package/substrate/standards/dependency-discipline/pip.md +0 -42
  230. package/substrate/standards/deployment-topology/ec2-tailscale.md +0 -225
  231. package/substrate/standards/deployment-topology.md +0 -69
  232. package/substrate/standards/docs-sync-allowlist.md +0 -76
  233. package/substrate/standards/domain-and-dns.md +0 -145
  234. package/substrate/standards/frontend-stack.md +0 -67
  235. package/substrate/standards/frontmatter-schema.md +0 -154
  236. package/substrate/standards/graceful-exit.md +0 -227
  237. package/substrate/standards/hook-idempotency.md +0 -102
  238. package/substrate/standards/hook-injection-discipline.md +0 -202
  239. package/substrate/standards/hook-install-class.md +0 -215
  240. package/substrate/standards/input-handler-interface.md +0 -152
  241. package/substrate/standards/lite-manifest-schema-changes.md +0 -135
  242. package/substrate/standards/luminary-matching.md +0 -105
  243. package/substrate/standards/luminary-problem-patterns.md +0 -481
  244. package/substrate/standards/migration-discipline/active-record.md +0 -50
  245. package/substrate/standards/migration-discipline/alembic.md +0 -43
  246. package/substrate/standards/migration-discipline/gorm.md +0 -50
  247. package/substrate/standards/migration-discipline/prisma.md +0 -53
  248. package/substrate/standards/migration-discipline/sqlalchemy.md +0 -51
  249. package/substrate/standards/mobile-ephemeral-session.md +0 -167
  250. package/substrate/standards/model-routing-discipline.md +0 -160
  251. package/substrate/standards/ogilvy-writing-rules.md +0 -225
  252. package/substrate/standards/opener-discipline.md +0 -96
  253. package/substrate/standards/operator-facing-prose-discipline.md +0 -201
  254. package/substrate/standards/persona-schema.md +0 -229
  255. package/substrate/standards/pluggable-luminaries.md +0 -323
  256. package/substrate/standards/pr-body-discipline.md +0 -115
  257. package/substrate/standards/preview-state-schema.md +0 -189
  258. package/substrate/standards/project-directory-layout.md +0 -276
  259. package/substrate/standards/release-tagging.md +0 -137
  260. package/substrate/standards/reserved-skill-names.md +0 -120
  261. package/substrate/standards/scannable-multi-option-output.md +0 -261
  262. package/substrate/standards/sdlc-compliance.md +0 -286
  263. package/substrate/standards/sdlc-gates/typescript.md +0 -57
  264. package/substrate/standards/secrets-lifecycle.md +0 -210
  265. package/substrate/standards/security-scanner-adapter.md +0 -145
  266. package/substrate/standards/session-board.md +0 -256
  267. package/substrate/standards/skill-output-discipline.md +0 -90
  268. package/substrate/standards/state-spine-contract.md +0 -255
  269. package/substrate/standards/state-spine.md +0 -511
  270. package/substrate/standards/steering-hints/kiss-words.md +0 -11
  271. package/substrate/standards/substrate-config-schema.md +0 -267
  272. package/substrate/standards/tech-stack-config.md +0 -109
  273. package/substrate/standards/tier-dependency-analysis.md +0 -167
  274. package/substrate/standards/tier-runtime-deps/lite.md +0 -57
  275. package/substrate/standards/tier-tag-schema.md +0 -155
  276. package/substrate/standards/two-layer-config.md +0 -99
  277. package/substrate/standards/use-case-format.md +0 -292
  278. package/substrate/standards/user-story-invest.md +0 -268
  279. package/substrate/standards/velocity-and-appetite.md +0 -229
  280. package/substrate/standards/voice-input-pattern.md +0 -119
  281. package/substrate/standards/whereami-schema.md +0 -301
  282. package/substrate/standards/worktree-management.md +0 -211
  283. package/substrate/standards/writing-guide.md +0 -213
  284. package/substrate/templates/chronicle-template.md +0 -75
  285. package/substrate/templates/deferred-action-template.md +0 -45
  286. package/substrate/templates/memory-proposal-template.md +0 -77
  287. package/substrate/templates/persona-template.md +0 -200
  288. package/substrate/templates/pr-faq.md +0 -45
  289. package/substrate/templates/secret-rotation-template.md +0 -162
  290. package/substrate/templates/spec-template.md +0 -131
  291. package/substrate/templates/use-case-template.md +0 -194
  292. package/substrate/templates/user-story-template.md +0 -107
  293. package/substrate/templates/whereami-template.md +0 -101
@@ -1,147 +0,0 @@
1
- #!/usr/bin/env bash
2
- # tier: lite
3
- # temperance-gate.sh — mechanical /temperance firing at decision boundaries
4
- # (bassclef#1147 T15)
5
- #
6
- # Fires on PreToolUse Edit|Write|MultiEdit. MVP scope: ONE trigger active —
7
- # "load-bearing path edit" (catches edits to .claude/, standards/, lib/state.sh,
8
- # SKILL.md when no fresh temperance marker exists for the session).
9
- #
10
- # Other triggers from bet 2026-06-18b WU-7 acceptance — explain-mode entry,
11
- # chain-anchor entry, non-stacked-branch first edit, post-compaction recovery —
12
- # are scaffolded as stubs below; design + implementation deferred to follow-on
13
- # tickets pending operator review of the trigger taxonomy.
14
- #
15
- # Other triggers from ticket #1147 — first-source-edit per session, N
16
- # consecutive edits without temperance, substrate proposal without catalog
17
- # browse, diagnose-repro marker absence — also deferred to follow-on.
18
- #
19
- # Coordinates with pre-build-gate.sh — that hook already handles
20
- # non-stacked-branch first edit temperance. This hook adds the load-bearing
21
- # trigger which pre-build-gate does not cover.
22
- #
23
- # Exit codes:
24
- # 0 — pass (override, skip, marker present, non-trigger)
25
- # 3 — BLOCK (load-bearing edit without temperance marker)
26
- #
27
- # Override: SKIP_TEMPERANCE_GATE=1 — logged via trace-helper (bassclef idiom).
28
-
29
- set -u
30
-
31
- # --- Override path ---
32
- if [ "${SKIP_TEMPERANCE_GATE:-0}" = "1" ]; then
33
- echo "SKIP_TEMPERANCE_GATE=1 — temperance gate bypassed" >&2
34
- exit 0
35
- fi
36
-
37
- # --- Read stdin (fail-soft on malformed JSON) ---
38
- INPUT=$(cat)
39
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null || echo "")
40
- FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null || echo "")
41
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null || echo "unknown")
42
- CWD=$(echo "$INPUT" | jq -r '.cwd // "."' 2>/dev/null || echo ".")
43
-
44
- if [ -z "$TOOL_NAME" ]; then
45
- exit 0
46
- fi
47
-
48
- # --- Tool-name matcher ---
49
- case "$TOOL_NAME" in
50
- Edit|Write|MultiEdit) ;;
51
- *) exit 0 ;;
52
- esac
53
-
54
- # --- Trigger 1: Load-bearing path edit (MVP — only active trigger) ---
55
- # Detects edits to substrate paths whose changes carry blast-radius beyond a
56
- # normal source edit. The temperance question forces the agent to articulate
57
- # "right thing" + "right way" before the edit lands.
58
-
59
- is_load_bearing() {
60
- local path="$1"
61
- case "$path" in
62
- */.claude/*) return 0 ;;
63
- */standards/*) return 0 ;;
64
- */lib/state.sh) return 0 ;;
65
- */SKILL.md) return 0 ;;
66
- .claude/*) return 0 ;;
67
- standards/*) return 0 ;;
68
- lib/state.sh) return 0 ;;
69
- *) return 1 ;;
70
- esac
71
- }
72
-
73
- # --- Trigger stubs (deferred to follow-on tickets) ---
74
- # Each stub is a function that always returns "no trigger" — the design +
75
- # implementation lands in a follow-on ticket. Listed here so reviewers can
76
- # see the planned trigger surface without reading the goal doc.
77
-
78
- trigger_explain_mode() { return 1; } # bet 2026-06-18b WU-7
79
- trigger_chain_anchor() { return 1; } # bet 2026-06-18b WU-7
80
- trigger_non_stacked_first_edit() { return 1; } # bet 2026-06-18b WU-7 (overlaps pre-build-gate; routing TBD)
81
- trigger_post_compaction() { return 1; } # bet 2026-06-18b WU-7
82
- trigger_n_consecutive_edits() { return 1; } # ticket #1147 trigger 3
83
- trigger_substrate_proposal() { return 1; } # ticket #1147 trigger 5
84
- trigger_diagnose_repro() { return 1; } # ticket #1147 trigger 6
85
-
86
- # --- Marker check for active trigger ---
87
- if ! is_load_bearing "$FILE_PATH"; then
88
- exit 0
89
- fi
90
-
91
- # Marker convention shared with pre-build-gate.sh — same temperance markers.
92
- # A fresh temperance marker (any branch this session) clears all triggers.
93
- MARKER_DIR="${CWD}/state/markers/temperance"
94
- SESSION_MARKER="${MARKER_DIR}/${SESSION_ID}.marker"
95
-
96
- if [ -f "$SESSION_MARKER" ]; then
97
- exit 0
98
- fi
99
-
100
- # Also clear when any temperance marker exists for the current branch (the
101
- # pre-build-gate convention writes branch-slug markers).
102
- if [ -d "$MARKER_DIR" ] && [ -n "$(ls -A "$MARKER_DIR" 2>/dev/null)" ]; then
103
- # Marker exists for some branch this session — pass. (Reviewer: this is
104
- # the loose check; tighter "matching branch" check is a follow-on.)
105
- exit 0
106
- fi
107
-
108
- # --- BLOCK ---
109
- cat >&2 <<BLOCK
110
- ============================================
111
- 🛑 temperance-gate — BLOCKED (essential path)
112
- ============================================
113
-
114
- About to edit an essential substrate path without a fresh temperance marker:
115
- ${FILE_PATH}
116
-
117
- The temperance question:
118
- Am I building the RIGHT THING?
119
- Am I building it the RIGHT WAY?
120
-
121
- Essential paths (.claude/, standards/, lib/state.sh, SKILL.md) carry
122
- more impact than a normal source edit. Pause and answer the two
123
- questions before the edit lands.
124
-
125
- To proceed:
126
- 1. State the answers (right thing / right way / what could break).
127
- 2. Write a temperance marker:
128
- mkdir -p ${MARKER_DIR}
129
- cat > ${SESSION_MARKER} <<EOF
130
- {"session_id":"${SESSION_ID}","entered_at":"\$(date -u +%Y-%m-%dT%H:%M:%SZ)","question_answered":"yes"}
131
- EOF
132
- 3. Re-run the edit — the marker now satisfies the gate.
133
-
134
- Override (logged):
135
- SKIP_TEMPERANCE_GATE=1 <command>
136
-
137
- Note: this is the MVP trigger (load-bearing path). Other triggers
138
- (explain-mode, chain-anchor, post-compaction, non-stacked first edit,
139
- N consecutive edits, substrate proposal, diagnose-repro) are scaffolded
140
- in this hook but inactive — they ship in follow-on tickets.
141
-
142
- Per bassclef#1147 T15 (this hook) and .claude/skills/temperance/SKILL.md
143
- (the methodology this gate enforces mechanically).
144
- ============================================
145
- BLOCK
146
-
147
- exit 3
@@ -1,233 +0,0 @@
1
- #!/bin/bash
2
- # tier: lite
3
- # testing-tier-enforce.sh — per-path testing-tier enforcement (bassclef#1037)
4
- #
5
- # Reads tier config from .claude/bassclef-configs.jsonc (testing.global_floor
6
- # + testing.path_matchers); per-file overrides from .claude/hooks/testing-tier-
7
- # enforce-allowlist.txt (grandfather grace) and state/testing-tier-overrides.jsonl
8
- # (operator-filed per-file tier flip — future; not yet read in v1).
9
- #
10
- # Tier semantics (per .claude/rules/testing-tier-config.md):
11
- # 0 strict TDD — BLOCK when sibling test absent OR test mtime < source mtime
12
- # 1 test-with — WARN when sibling test absent
13
- # 2 smoke — silent (advisory only)
14
- # 3 manual verify — silent
15
- #
16
- # Path-matcher precedence: array order is most-specific to least-specific; first
17
- # match wins. When no entry matches, testing.global_floor applies (default 1).
18
- #
19
- # Sibling test convention (Tier 0 only):
20
- # .claude/hooks/<name>.sh -> .claude/hooks/tests/<name>.test.sh
21
- # standards/.../schemas/<name>.json -> standards/.../schemas/tests/<name>.test.sh
22
- # lib/<name>.sh -> lib/tests/<name>.test.sh
23
- #
24
- # Override: SKIP_TESTING_TIER_ENFORCE=1 — bypass entire hook for one command.
25
- # Logged via trace-helper.sh per bassclef's existing override idiom.
26
- #
27
- # Wired into pre-commit-gate.sh chain. Also invokable standalone for tests
28
- # (set TESTING_TIER_FILES env var with newline-separated paths to check
29
- # instead of reading staged files from git).
30
-
31
- set -u
32
-
33
- REPO_ROOT="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
34
- CONFIG_FILE="$REPO_ROOT/.claude/bassclef-configs.jsonc"
35
- ALLOWLIST_FILE="$REPO_ROOT/.claude/hooks/testing-tier-enforce-allowlist.txt"
36
-
37
- # Override path
38
- if [ "${SKIP_TESTING_TIER_ENFORCE:-0}" = "1" ]; then
39
- if [ -f "$REPO_ROOT/.claude/hooks/trace-helper.sh" ]; then
40
- # shellcheck disable=SC1091
41
- source "$REPO_ROOT/.claude/hooks/trace-helper.sh" 2>/dev/null || true
42
- type trace_log >/dev/null 2>&1 && trace_log "testing-tier-enforce" "SKIP_TESTING_TIER_ENFORCE=1 bypass"
43
- fi
44
- exit 0
45
- fi
46
-
47
- # resolve_tier_for_path <relative-path> -> echoes tier int (0/1/2/3)
48
- resolve_tier_for_path() {
49
- local path="$1"
50
- if [ ! -f "$CONFIG_FILE" ]; then
51
- echo 1
52
- return
53
- fi
54
- local json
55
- json=$(perl -pe 's,^\s*//.*$,,; s,/\*.*?\*/,,g' "$CONFIG_FILE" 2>/dev/null)
56
- local global_floor
57
- global_floor=$(echo "$json" | jq -r '.testing.global_floor // 1' 2>/dev/null)
58
- [ -z "$global_floor" ] || [ "$global_floor" = "null" ] && global_floor=1
59
-
60
- # Iterate matchers in array order; first shell-glob match wins.
61
- local count
62
- count=$(echo "$json" | jq -r '.testing.path_matchers | length // 0' 2>/dev/null)
63
- [ -z "$count" ] || [ "$count" = "null" ] && count=0
64
-
65
- local i=0
66
- while [ "$i" -lt "$count" ]; do
67
- local pattern tier
68
- pattern=$(echo "$json" | jq -r ".testing.path_matchers[$i].match" 2>/dev/null)
69
- tier=$(echo "$json" | jq -r ".testing.path_matchers[$i].tier" 2>/dev/null)
70
- # Shell glob via case statement; ** treated as * (bash glob limitation OK for v1)
71
- # Replace ** with * for case matching
72
- local case_pattern="${pattern//\*\*/\*}"
73
- case "$path" in
74
- $case_pattern)
75
- echo "$tier"
76
- return
77
- ;;
78
- esac
79
- i=$((i + 1))
80
- done
81
-
82
- echo "$global_floor"
83
- }
84
-
85
- # is_allowlisted_in_grace <relative-path> -> exit 0 if grace covers
86
- is_allowlisted_in_grace() {
87
- local path="$1"
88
- [ ! -f "$ALLOWLIST_FILE" ] && return 1
89
- local now
90
- now=$(date -u +%s)
91
- while IFS='|' read -r entry_path grace_until; do
92
- [ -z "${entry_path:-}" ] && continue
93
- case "$entry_path" in '#'*|'') continue ;; esac
94
- # Trim whitespace
95
- entry_path="${entry_path# }"; entry_path="${entry_path% }"
96
- grace_until="${grace_until# }"; grace_until="${grace_until% }"
97
- [ "$entry_path" != "$path" ] && continue
98
- local grace_epoch=""
99
- grace_epoch=$(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$grace_until" +%s 2>/dev/null) || \
100
- grace_epoch=$(date -u -d "$grace_until" +%s 2>/dev/null) || \
101
- grace_epoch=""
102
- [ -z "$grace_epoch" ] && return 1
103
- [ "$now" -lt "$grace_epoch" ] && return 0
104
- return 1
105
- done < "$ALLOWLIST_FILE"
106
- return 1
107
- }
108
-
109
- # sibling_test_path <source-relative-path> -> echoes expected test path
110
- sibling_test_path() {
111
- local src="$1"
112
- local dir base stem
113
- dir=$(dirname "$src")
114
- base=$(basename "$src")
115
- stem="${base%.*}"
116
- echo "${dir}/tests/${stem}.test.sh"
117
- }
118
-
119
- # Get file mtime as epoch seconds (portable Mac + Linux).
120
- # GNU stat is tried first because BSD-style `stat -f %m` on Linux GNU
121
- # does NOT fail — it succeeds with mount-point output (%m means mount
122
- # point under GNU's -f filesystem mode), which would silently corrupt
123
- # the mtime comparison. GNU-first; BSD fallback for macOS.
124
- file_mtime() {
125
- local f="$1"
126
- stat -c %Y "$f" 2>/dev/null || stat -f %m "$f" 2>/dev/null
127
- }
128
-
129
- # check_tier_0_violation <relative-path> -> exit 0 if ok, 1 if violation
130
- # Sets REASON var with violation description.
131
- check_tier_0_violation() {
132
- local src="$1"
133
- local test_rel test_abs src_abs
134
- test_rel=$(sibling_test_path "$src")
135
- test_abs="$REPO_ROOT/$test_rel"
136
- src_abs="$REPO_ROOT/$src"
137
-
138
- if [ ! -f "$test_abs" ]; then
139
- REASON="Tier 0 source has no sibling test at $test_rel — write the test first per TDD discipline"
140
- return 1
141
- fi
142
- local src_mtime test_mtime
143
- src_mtime=$(file_mtime "$src_abs")
144
- test_mtime=$(file_mtime "$test_abs")
145
- if [ -z "$src_mtime" ] || [ -z "$test_mtime" ]; then
146
- REASON="Tier 0 mtime check failed: could not read mtimes (src=$src test=$test_rel)"
147
- return 1
148
- fi
149
- if [ "$test_mtime" -lt "$src_mtime" ]; then
150
- REASON="Tier 0 source modified ($src) but test ($test_rel) mtime did not advance — write the test before the source per TDD discipline"
151
- return 1
152
- fi
153
- return 0
154
- }
155
-
156
- main() {
157
- local files
158
- if [ -n "${TESTING_TIER_FILES:-}" ]; then
159
- files="$TESTING_TIER_FILES"
160
- else
161
- # Read PreToolUse hook payload (jsonpath .tool_input.command) from stdin if present
162
- if [ ! -t 0 ]; then
163
- local input command
164
- input=$(cat 2>/dev/null || echo '')
165
- if [ -n "$input" ]; then
166
- command=$(echo "$input" | jq -r '.tool_input.command // ""' 2>/dev/null || echo '')
167
- if ! echo "$command" | grep -q 'git commit'; then
168
- exit 0
169
- fi
170
- fi
171
- fi
172
- files=$(git -C "$REPO_ROOT" diff --cached --name-only --diff-filter=AM 2>/dev/null || echo '')
173
- fi
174
-
175
- [ -z "$files" ] && exit 0
176
-
177
- local blocks=()
178
- local warnings=()
179
-
180
- while IFS= read -r f; do
181
- [ -z "$f" ] && continue
182
- local tier
183
- tier=$(resolve_tier_for_path "$f")
184
- case "$tier" in
185
- 0)
186
- if is_allowlisted_in_grace "$f"; then
187
- continue
188
- fi
189
- REASON=""
190
- if ! check_tier_0_violation "$f"; then
191
- blocks+=("$f: $REASON")
192
- fi
193
- ;;
194
- 1)
195
- local exp_test
196
- exp_test=$(sibling_test_path "$f")
197
- if [ ! -f "$REPO_ROOT/$exp_test" ]; then
198
- warnings+=("$f: Tier 1 — no sibling test at $exp_test (expected; not BLOCKing)")
199
- fi
200
- ;;
201
- 2|3)
202
- : ;;
203
- esac
204
- done <<< "$files"
205
-
206
- if [ "${#warnings[@]}" -gt 0 ]; then
207
- # Advisory only — write to stdout so the Claude Code PreToolUse
208
- # wrapper does not treat non-empty stderr as an error and block
209
- # the git commit. BLOCK output below stays on stderr (real error).
210
- echo ""
211
- echo "TESTING-TIER WARN (Tier 1):"
212
- for w in "${warnings[@]}"; do echo " $w"; done
213
- fi
214
-
215
- if [ "${#blocks[@]}" -gt 0 ]; then
216
- echo "" >&2
217
- echo "============================================" >&2
218
- echo "🛑 TESTING-TIER ENFORCE — BLOCKED 🛑" >&2
219
- echo "============================================" >&2
220
- for b in "${blocks[@]}"; do echo " $b" >&2; done
221
- echo "" >&2
222
- echo "Per .claude/rules/testing-tier-config.md (bassclef#1037)." >&2
223
- echo "Tier framework: 0 strict TDD / 1 WARN / 2 smoke / 3 manual verify." >&2
224
- echo "Resolution: write the sibling test FIRST, then re-stage and commit." >&2
225
- echo "Override (logged): SKIP_TESTING_TIER_ENFORCE=1 <command>" >&2
226
- echo "============================================" >&2
227
- exit 1
228
- fi
229
-
230
- exit 0
231
- }
232
-
233
- main
@@ -1,219 +0,0 @@
1
- #!/bin/bash
2
- # tier: lite
3
- # install-class: dual
4
- # Turn-prose grade measure — Stop hook that reads the last assistant message
5
- # from the transcript, computes its Flesch-Kincaid grade level, and writes
6
- # the number to a marker file at state/markers/turn-grade/last-turn.json.
7
- #
8
- # The pre-turn plain-english-steering.sh reads the marker and injects the
9
- # number into the steering block on the next prompt. Turns a soft "aim for
10
- # grade 10" reminder into a concrete number the agent sees each turn.
11
- #
12
- # Complements turn-prose-kiss-check.sh — that hook scans for BLOCK words.
13
- # This hook measures reading level.
14
- #
15
- # Input (stdin): JSON with transcript_path + session_id
16
- # Output: writes state/markers/turn-grade/last-turn.json
17
- # Exit: 0 always (measurement only, no gate)
18
- #
19
- # Override: SKIP_TURN_PROSE_GRADE=1
20
-
21
- set +e
22
-
23
- # === Override path ===
24
- if [ "${SKIP_TURN_PROSE_GRADE:-0}" = "1" ]; then
25
- exit 0
26
- fi
27
-
28
- # === Parse stdin JSON ===
29
- STDIN_JSON=$(cat 2>/dev/null || echo '{}')
30
- TRANSCRIPT_PATH=$(echo "$STDIN_JSON" | jq -r '.transcript_path // ""' 2>/dev/null)
31
-
32
- [ -z "$TRANSCRIPT_PATH" ] && exit 0
33
- [ ! -f "$TRANSCRIPT_PATH" ] && exit 0
34
-
35
- # === Extract last assistant text ===
36
- LAST_ASSISTANT_LINE=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null | tail -1)
37
- [ -z "$LAST_ASSISTANT_LINE" ] && exit 0
38
-
39
- MESSAGE_TEXT=$(echo "$LAST_ASSISTANT_LINE" \
40
- | jq -r '.message.content[]? | select(.type == "text") | .text' 2>/dev/null)
41
- [ -z "$MESSAGE_TEXT" ] && exit 0
42
-
43
- # === Strip code blocks + inline backticks + URLs (prose only) ===
44
- SCRUBBED=$(echo "$MESSAGE_TEXT" | awk '
45
- BEGIN { in_code = 0 }
46
- /^```/ { in_code = !in_code; next }
47
- in_code { next }
48
- { print }
49
- ' | sed -E 's/`[^`]*`//g; s|https?://[^ )]+||g')
50
-
51
- # === Compute Flesch-Kincaid grade via python ===
52
- # Try textstat first (accurate; well-tested syllable counter). Fall back to
53
- # hand-rolled formula when textstat is not installed. Zero break for adopters
54
- # who have not installed the library.
55
- # Per Ship 1 #1312: also compute per-sentence grade + top 3 offenders that
56
- # exceed grade 10. Output as JSON for bash to inject into marker.
57
- GRADE_OUTPUT=$(printf '%s' "$SCRUBBED" | python3 -c '
58
- import sys, re, json
59
-
60
- text = sys.stdin.read()
61
-
62
- sentences = [s for s in re.split(r"[.!?]+", text) if s.strip()]
63
- words = re.findall(r"\b[a-zA-Z][a-zA-Z\x27]*\b", text)
64
-
65
- if len(words) < 20 or not sentences:
66
- print("SKIP")
67
- sys.exit(0)
68
-
69
- # Fallback syllable counter — always defined so per-sentence path works
70
- def count_syllables(word):
71
- word = re.sub(r"[^a-z]", "", word.lower())
72
- if not word:
73
- return 0
74
- vowels = "aeiouy"
75
- count = 0
76
- prev_was_vowel = False
77
- for c in word:
78
- is_vowel = c in vowels
79
- if is_vowel and not prev_was_vowel:
80
- count += 1
81
- prev_was_vowel = is_vowel
82
- if word.endswith("e") and count > 1:
83
- count -= 1
84
- return max(1, count)
85
-
86
- # Preferred path — textstat library
87
- try:
88
- from textstat import flesch_kincaid_grade, syllable_count
89
- grade = flesch_kincaid_grade(text)
90
- syllables = syllable_count(text)
91
- source = "TEXTSTAT"
92
- def sentence_grade(s):
93
- return flesch_kincaid_grade(s)
94
- except ImportError:
95
- syllables = sum(count_syllables(w) for w in words)
96
- grade = 0.39 * (len(words) / len(sentences)) + 11.8 * (syllables / len(words)) - 15.59
97
- source = "FALLBACK"
98
- def sentence_grade(s):
99
- s_words = re.findall(r"\b[a-zA-Z][a-zA-Z\x27]*\b", s)
100
- if not s_words:
101
- return 0
102
- s_syllables = sum(count_syllables(w) for w in s_words)
103
- # For a single sentence, sentence-count is 1
104
- return 0.39 * len(s_words) + 11.8 * (s_syllables / len(s_words)) - 15.59
105
-
106
- # Per-sentence offenders — Ship 1 #1312
107
- offenders = []
108
- for s in sentences:
109
- s_clean = s.strip()
110
- s_words = re.findall(r"\b[a-zA-Z][a-zA-Z\x27]*\b", s_clean)
111
- if len(s_words) < 5:
112
- continue # skip very short sentences
113
- try:
114
- s_grade = sentence_grade(s_clean)
115
- except Exception:
116
- continue
117
- if s_grade > 10:
118
- preview = s_clean[:80]
119
- if len(s_clean) > 80:
120
- preview += "..."
121
- offenders.append({
122
- "grade": round(s_grade, 1),
123
- "words": len(s_words),
124
- "preview": preview,
125
- })
126
- # Sort by grade descending; take top 3
127
- offenders.sort(key=lambda x: -x["grade"])
128
- offenders = offenders[:3]
129
-
130
- # Emit first line = original space-separated shape for backward compat
131
- print(f"{grade:.1f} {len(words)} {len(sentences)} {syllables} {source}")
132
- # Emit second line = JSON array of offenders (may be empty)
133
- print(json.dumps(offenders))
134
- ' 2>/dev/null)
135
-
136
- # Parse output — either "SKIP" or "grade words sentences syllables SOURCE" + offenders JSON
137
- if [ -z "$GRADE_OUTPUT" ] || [ "$GRADE_OUTPUT" = "SKIP" ]; then
138
- exit 0
139
- fi
140
-
141
- # First line = grade metrics; second line = offenders JSON
142
- GRADE_LINE=$(echo "$GRADE_OUTPUT" | head -1)
143
- OFFENDERS_JSON=$(echo "$GRADE_OUTPUT" | sed -n '2p')
144
- [ -z "$OFFENDERS_JSON" ] && OFFENDERS_JSON="[]"
145
-
146
- GRADE=$(echo "$GRADE_LINE" | awk '{print $1}')
147
- WORDS=$(echo "$GRADE_LINE" | awk '{print $2}')
148
- SENTENCES=$(echo "$GRADE_LINE" | awk '{print $3}')
149
- SOURCE=$(echo "$GRADE_LINE" | awk '{print $5}')
150
-
151
- [ -z "$GRADE" ] && exit 0
152
-
153
- # === Write grade marker ===
154
- REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
155
- MARKER_DIR="${REPO_ROOT}/state/markers/turn-grade"
156
- mkdir -p "$MARKER_DIR" 2>/dev/null
157
-
158
- cat > "${MARKER_DIR}/last-turn.json" 2>/dev/null <<EOF
159
- {
160
- "grade": $GRADE,
161
- "words": $WORDS,
162
- "sentences": $SENTENCES,
163
- "measured_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
164
- "target_ceiling": 10,
165
- "target_aspiration": 8,
166
- "source": "${SOURCE:-UNKNOWN}",
167
- "top_offenders": ${OFFENDERS_JSON}
168
- }
169
- EOF
170
-
171
- # === Rewrite-check hits marker (ticket #935 extension) ===
172
- # Run lib/rewrite-check.sh on the scrubbed text; count hits per category.
173
- # Write to state/markers/turn-prose-flags/last-turn.json for plain-english-steering.sh
174
- # to read on the next turn and inject as first-person compose reminders.
175
- FLAGS_DIR="${REPO_ROOT}/state/markers/turn-prose-flags"
176
- REWRITE_LIB="${REPO_ROOT}/lib/rewrite-check.sh"
177
-
178
- if [ -f "$REWRITE_LIB" ]; then
179
- mkdir -p "$FLAGS_DIR" 2>/dev/null
180
- TMP_TEXT=$(mktemp)
181
- printf '%s' "$SCRUBBED" > "$TMP_TEXT"
182
-
183
- # shellcheck disable=SC1090
184
- source "$REWRITE_LIB" 2>/dev/null
185
-
186
- # Count hits per check function (each prints one match per line)
187
- PASSIVE_HITS=0
188
- HYPHEN_HITS=0
189
- LONG_SENTENCE_HITS=0
190
- ADVERB_HITS=0
191
-
192
- if declare -f check_passive_voice >/dev/null 2>&1; then
193
- PASSIVE_HITS=$(check_passive_voice "$TMP_TEXT" 2>/dev/null | wc -l | tr -d ' ')
194
- fi
195
- if declare -f check_hyphen_words >/dev/null 2>&1; then
196
- HYPHEN_HITS=$(check_hyphen_words "$TMP_TEXT" 2>/dev/null | wc -l | tr -d ' ')
197
- fi
198
- if declare -f check_sentence_length >/dev/null 2>&1; then
199
- LONG_SENTENCE_HITS=$(check_sentence_length "$TMP_TEXT" 25 2>/dev/null | wc -l | tr -d ' ')
200
- fi
201
- if declare -f check_adverb_density >/dev/null 2>&1; then
202
- ADVERB_HITS=$(check_adverb_density "$TMP_TEXT" 2>/dev/null | wc -l | tr -d ' ')
203
- fi
204
-
205
- rm -f "$TMP_TEXT"
206
-
207
- cat > "${FLAGS_DIR}/last-turn.json" 2>/dev/null <<EOF
208
- {
209
- "total_words": $WORDS,
210
- "long_sentences": $LONG_SENTENCE_HITS,
211
- "passive_voice": $PASSIVE_HITS,
212
- "hyphen_words": $HYPHEN_HITS,
213
- "adverbs": $ADVERB_HITS,
214
- "measured_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
215
- }
216
- EOF
217
- fi
218
-
219
- exit 0