@windyroad/style-guide 0.2.1 → 0.3.0-preview.176

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "wr-style-guide",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Style guide enforcement for Claude Code"
5
- }
5
+ }
@@ -0,0 +1,46 @@
1
+ #!/bin/bash
2
+ # Shared session-announcement marker helpers (P095 / ADR-038).
3
+ #
4
+ # Used by UserPromptSubmit hooks to gate verbose MANDATORY instruction
5
+ # prose behind a once-per-session check. First prompt of a session emits
6
+ # the full block AND calls mark_announced; subsequent prompts see the
7
+ # marker via has_announced and emit only a terse reminder.
8
+ #
9
+ # Why no TTL or drift check (unlike review-gate.sh): announcement is
10
+ # bookkeeping for prose verbosity, not enforcement. PreToolUse gates
11
+ # still block unauthorised edits regardless of announcement state; the
12
+ # delegated agent re-reads policy when it runs. Extending the marker's
13
+ # lifetime across policy changes mid-session is safe — the gate, not
14
+ # the announcement, is load-bearing.
15
+ #
16
+ # Marker path convention: /tmp/${SYSTEM}-announced-${SESSION_ID}
17
+ # (mirrors the /tmp/${SYSTEM}-reviewed-${SESSION_ID} convention from
18
+ # style-guide/voice-tone/risk-scorer review-gate.sh; the -announced-
19
+ # suffix distinguishes announcement markers from clearance markers).
20
+ #
21
+ # Empty SESSION_ID fallback: has_announced returns 1 (not announced,
22
+ # full block emits) and mark_announced is a no-op (no file written).
23
+ # This covers manual hook invocation, test harnesses, and any rare
24
+ # case where Claude Code does not pass a session_id on stdin.
25
+
26
+ # Returns 0 if the hook for SYSTEM has already announced in SESSION_ID,
27
+ # 1 otherwise. Empty SESSION_ID => returns 1 (never announced).
28
+ #
29
+ # Usage: has_announced "architect" "$SESSION_ID"
30
+ has_announced() {
31
+ local SYSTEM="$1"
32
+ local SESSION_ID="$2"
33
+ [ -n "$SESSION_ID" ] || return 1
34
+ [ -f "/tmp/${SYSTEM}-announced-${SESSION_ID}" ]
35
+ }
36
+
37
+ # Writes the announcement marker for SYSTEM in SESSION_ID. Empty
38
+ # SESSION_ID => no-op. Safe to call more than once per session.
39
+ #
40
+ # Usage: mark_announced "architect" "$SESSION_ID"
41
+ mark_announced() {
42
+ local SYSTEM="$1"
43
+ local SESSION_ID="$2"
44
+ [ -n "$SESSION_ID" ] || return 0
45
+ : > "/tmp/${SYSTEM}-announced-${SESSION_ID}"
46
+ }
@@ -1,10 +1,25 @@
1
1
  #!/bin/bash
2
- # Style Guide - UserPromptSubmit hook
2
+ # Style Guide - UserPromptSubmit hook (P095 / ADR-038)
3
3
  # Detects STYLE-GUIDE.md in the project and injects delegation instruction.
4
4
  # If the file doesn't exist, instructs Claude to create it via the agent.
5
+ #
6
+ # Progressive disclosure (ADR-038): full MANDATORY block on first
7
+ # prompt; terse reminder on subsequent prompts in the same session.
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ # shellcheck source=lib/session-marker.sh
11
+ source "$SCRIPT_DIR/lib/session-marker.sh"
12
+
13
+ INPUT=$(cat)
14
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null || echo "")
5
15
 
6
16
  if [ -f "docs/STYLE-GUIDE.md" ]; then
7
- cat <<'HOOK_OUTPUT'
17
+ if has_announced "style-guide" "$SESSION_ID"; then
18
+ cat <<'HOOK_OUTPUT'
19
+ MANDATORY style-guide gate active (docs/STYLE-GUIDE.md present). Delegate to wr-style-guide:agent before editing UI files (.css, .html, .jsx, .tsx, .vue, .svelte, .ejs, .hbs). See turn-1 instructions for full scope.
20
+ HOOK_OUTPUT
21
+ else
22
+ cat <<'HOOK_OUTPUT'
8
23
  INSTRUCTION: MANDATORY STYLE GUIDE CHECK. YOU MUST FOLLOW THIS.
9
24
  DETECTED: docs/STYLE-GUIDE.md exists in this project.
10
25
 
@@ -22,6 +37,8 @@ REQUIRED ACTIONS:
22
37
  SCOPE: All .css and UI component files (.html, .jsx, .tsx, .vue, .svelte, .ejs, .hbs).
23
38
  Does NOT apply to: .ts/.js backend files, .md files, config files.
24
39
  HOOK_OUTPUT
40
+ mark_announced "style-guide" "$SESSION_ID"
41
+ fi
25
42
  else
26
43
  # Check if this is a web project (has UI files)
27
44
  if ls src/**/*.tsx src/**/*.jsx src/**/*.css src/**/*.html 2>/dev/null | head -1 | grep -q .; then
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bats
2
+
3
+ # P095 / ADR-038: style-guide-eval.sh UserPromptSubmit hook must emit
4
+ # the full MANDATORY block only on the first prompt of a session;
5
+ # subsequent prompts emit a terse reminder.
6
+
7
+ setup() {
8
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
9
+ HOOK="$REPO_ROOT/packages/style-guide/hooks/style-guide-eval.sh"
10
+
11
+ WORKDIR="$(mktemp -d)"
12
+ mkdir -p "$WORKDIR/docs"
13
+ : > "$WORKDIR/docs/STYLE-GUIDE.md"
14
+
15
+ SID="sg-eval-test-$$-$RANDOM"
16
+ }
17
+
18
+ teardown() {
19
+ rm -f "/tmp/style-guide-announced-${SID}"
20
+ rm -f "/tmp/style-guide-announced-${SID}-alt"
21
+ rm -rf "$WORKDIR"
22
+ }
23
+
24
+ run_hook() {
25
+ local sid="$1"
26
+ (cd "$WORKDIR" && echo "{\"session_id\":\"$sid\"}" | bash "$HOOK")
27
+ }
28
+
29
+ @test "style-guide-eval: first invocation emits the full MANDATORY block" {
30
+ run run_hook "$SID"
31
+ [ "$status" -eq 0 ]
32
+ [ "${#output}" -gt 400 ]
33
+ [[ "$output" == *"MANDATORY STYLE GUIDE CHECK"* ]]
34
+ [[ "$output" == *"wr-style-guide:agent"* ]]
35
+ }
36
+
37
+ @test "style-guide-eval: first invocation writes the announcement marker" {
38
+ run run_hook "$SID"
39
+ [ -f "/tmp/style-guide-announced-${SID}" ]
40
+ }
41
+
42
+ @test "style-guide-eval: second invocation emits only a terse reminder" {
43
+ run_hook "$SID" >/dev/null
44
+ run run_hook "$SID"
45
+ [ "${#output}" -lt 250 ]
46
+ [[ "$output" == *"style-guide"* ]] || [[ "$output" == *"STYLE"* ]]
47
+ [[ "$output" == *"wr-style-guide:agent"* ]]
48
+ [[ "$output" != *"REQUIRED ACTIONS:"* ]]
49
+ }
50
+
51
+ @test "style-guide-eval: terse reminder preserves the MANDATORY signal word" {
52
+ run_hook "$SID" >/dev/null
53
+ run run_hook "$SID"
54
+ [[ "$output" == *"MANDATORY"* ]] || [[ "$output" == *"REQUIRED"* ]] || [[ "$output" == *"NON-OPTIONAL"* ]]
55
+ }
56
+
57
+ @test "style-guide-eval: terse reminder names the trigger artifact" {
58
+ run_hook "$SID" >/dev/null
59
+ run run_hook "$SID"
60
+ [[ "$output" == *"STYLE-GUIDE.md"* ]]
61
+ }
62
+
63
+ @test "style-guide-eval: different session_id re-emits the full block" {
64
+ run_hook "$SID" >/dev/null
65
+ local SID2="${SID}-alt"
66
+ run run_hook "$SID2"
67
+ [ "${#output}" -gt 400 ]
68
+ [[ "$output" == *"MANDATORY STYLE GUIDE CHECK"* ]]
69
+ rm -f "/tmp/style-guide-announced-${SID2}"
70
+ }
71
+
72
+ @test "style-guide-eval: empty session_id emits the full block and writes no marker" {
73
+ run run_hook ""
74
+ [ "${#output}" -gt 400 ]
75
+ [[ "$output" == *"MANDATORY STYLE GUIDE CHECK"* ]]
76
+ [ ! -f "/tmp/style-guide-announced-" ]
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/style-guide",
3
- "version": "0.2.1",
3
+ "version": "0.3.0-preview.176",
4
4
  "description": "Style guide enforcement for CSS and UI components",
5
5
  "bin": {
6
6
  "windyroad-style-guide": "./bin/install.mjs"