@windyroad/voice-tone 0.3.1 → 0.4.0-preview.303

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-voice-tone",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Voice and tone enforcement for Claude Code"
5
5
  }
package/README.md CHANGED
@@ -50,6 +50,22 @@ The `wr-voice-tone:agent` reads your `docs/VOICE-AND-TONE.md` and reviews propos
50
50
  - Banned words and patterns
51
51
  - Preferred terminology
52
52
 
53
+ ## Jobs to be Done
54
+
55
+ This plugin serves the [Jobs to be Done](../../docs/jtbd/) below. Per [ADR-051](../../docs/decisions/051-jtbd-anchored-readme-with-drift-advisory.proposed.md), the persona-grouped JTBD anchor is the canonical source of truth for the README's value framing.
56
+
57
+ ### Solo developer
58
+
59
+ - **[JTBD-001 Enforce Governance Without Slowing Down](../../docs/jtbd/solo-developer/JTBD-001-enforce-governance.proposed.md)** — voice-and-tone review fires automatically on every user-facing copy edit; the project's own voice guide is the policy source rather than the agent's defaults.
60
+
61
+ ### Tech lead / consultant
62
+
63
+ - **[JTBD-202 Run Pre-Flight Governance Checks Before Release or Handover](../../docs/jtbd/tech-lead/JTBD-202-pre-flight-governance-check.proposed.md)** — voice-and-tone alignment is reviewable on demand before a release or client handover.
64
+
65
+ ### Plugin user
66
+
67
+ - **[JTBD-302 Trust That the README Describes the Plugin I Just Installed](../../docs/jtbd/plugin-user/JTBD-302-trust-readme-describes-installed-behaviour.proposed.md)** — this README is anchored on current JTBD job IDs; drift between prose and shipped behaviour is detectable at retro time per ADR-051.
68
+
53
69
  ## Updating and Uninstalling
54
70
 
55
71
  ```bash
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bats
2
+
3
+ # Tests for voice-tone-enforce-edit.sh — verifies the path-based exemption
4
+ # for governance-managed surfaces (docs/story-maps/, docs/stories/) per
5
+ # ADR-060 § Phase 2 amendment 2026-05-12 lines 481-496 (P170 Phase 2 Slice 2.5).
6
+ #
7
+ # The voice-tone hook is opt-in (gates *.html|*.jsx|*.tsx|*.vue|*.svelte|
8
+ # *.ejs|*.hbs) and blocks outright when docs/VOICE-AND-TONE.md is absent.
9
+ # Story-map HTML files would otherwise be blocked even when no policy
10
+ # exists — this is the empirical block P170 line 297 documented when the
11
+ # STORY-MAP-001 bootstrap was attempted. The exemption short-circuits before
12
+ # the extension check.
13
+
14
+ setup() {
15
+ SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
16
+ HOOK="$SCRIPT_DIR/voice-tone-enforce-edit.sh"
17
+ ORIG_DIR="$PWD"
18
+ TEST_DIR=$(mktemp -d)
19
+ cd "$TEST_DIR"
20
+ }
21
+
22
+ teardown() {
23
+ cd "$ORIG_DIR"
24
+ rm -rf "$TEST_DIR"
25
+ }
26
+
27
+ run_hook_with_file() {
28
+ local file_path="$1"
29
+ local json="{\"tool_input\":{\"file_path\":\"${file_path}\"},\"session_id\":\"test-session-$$\"}"
30
+ echo "$json" | bash "$HOOK"
31
+ }
32
+
33
+ assert_path_allowed() {
34
+ local file_path="$1"
35
+ run run_hook_with_file "$file_path"
36
+ [ "$status" -eq 0 ]
37
+ [[ "$output" != *"BLOCKED"* ]]
38
+ }
39
+
40
+ assert_path_blocked() {
41
+ local file_path="$1"
42
+ run run_hook_with_file "$file_path"
43
+ [ "$status" -eq 0 ]
44
+ [[ "$output" == *"BLOCKED"* ]]
45
+ }
46
+
47
+ # --- Story maps + stories exemptions (P170 Phase 2 Slice 2.5 / ADR-060) ---
48
+
49
+ @test "voice-tone: exempts docs/story-maps/ HTML in per-state subdir" {
50
+ assert_path_allowed "$PWD/docs/story-maps/draft/STORY-MAP-001-foo.html"
51
+ }
52
+
53
+ @test "voice-tone: exempts docs/story-maps/ HTML in completed subdir" {
54
+ assert_path_allowed "$PWD/docs/story-maps/completed/STORY-MAP-002-bar.html"
55
+ }
56
+
57
+ @test "voice-tone: exempts docs/story-maps/ even when no VOICE-AND-TONE.md exists" {
58
+ # P170 line 297: STORY-MAP-001 bootstrap was blocked here exactly because
59
+ # this exemption did not exist. Behavioural regression-guard.
60
+ [ ! -f docs/VOICE-AND-TONE.md ]
61
+ assert_path_allowed "$PWD/docs/story-maps/in-progress/STORY-MAP-001-rfc-framework.html"
62
+ }
63
+
64
+ @test "voice-tone: exempts docs/stories/ files even though .md isn't normally gated" {
65
+ assert_path_allowed "$PWD/docs/stories/draft/STORY-001-foo.md"
66
+ }
67
+
68
+ # --- Regression: non-exempt HTML still gate ---
69
+
70
+ @test "voice-tone: still blocks an unrelated .html file when no policy exists" {
71
+ assert_path_blocked "$PWD/public/index.html"
72
+ }
73
+
74
+ @test "voice-tone: still blocks a .tsx component file when no policy exists" {
75
+ assert_path_blocked "$PWD/src/Component.tsx"
76
+ }
@@ -45,6 +45,20 @@ case "$FILE_PATH" in
45
45
  ;;
46
46
  esac
47
47
 
48
+ # Governance-managed surface exemptions — ADR-060 § Phase 2 amendment
49
+ # 2026-05-12 lines 481-496 (P170 Phase 2 Slice 2.5). Story-map HTML and
50
+ # story Markdown are governed by capture-story-map / manage-story-map and
51
+ # capture-story / manage-story skills (peer-plugin pattern, mirrors the
52
+ # docs/problems and docs/jtbd exemptions on architect + jtbd gates).
53
+ # Short-circuits before the *.html opt-in match below would otherwise fire
54
+ # on story-map HTML — the empirical block documented at P170 line 297.
55
+ case "$FILE_PATH" in
56
+ */docs/story-maps/*|docs/story-maps/*)
57
+ exit 0 ;;
58
+ */docs/stories/*|docs/stories/*)
59
+ exit 0 ;;
60
+ esac
61
+
48
62
  # Gate copy-bearing files
49
63
  case "$FILE_PATH" in
50
64
  *.html|*.jsx|*.tsx|*.vue|*.svelte|*.ejs|*.hbs) ;;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/voice-tone",
3
- "version": "0.3.1",
3
+ "version": "0.4.0-preview.303",
4
4
  "description": "Voice and tone enforcement for user-facing copy",
5
5
  "bin": {
6
6
  "windyroad-voice-tone": "./bin/install.mjs"