@windyroad/jtbd 0.12.0 → 0.12.1-preview.562

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.
@@ -90,5 +90,5 @@
90
90
  }
91
91
  },
92
92
  "name": "wr-jtbd",
93
- "version": "0.12.0"
93
+ "version": "0.12.1"
94
94
  }
@@ -10,6 +10,16 @@
10
10
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
11
  source "$SCRIPT_DIR/lib/review-gate.sh"
12
12
 
13
+ # P191: resolve the project root from the session signal, not the hook's
14
+ # runtime CWD. Claude Code may launch the hook with an actual working
15
+ # directory that differs from the session/project dir while still exporting
16
+ # CLAUDE_PROJECT_DIR (and a $PWD env var) pointing at the project. A relative
17
+ # `[ -d "docs/jtbd" ]` then false-negatives even though docs/jtbd is present,
18
+ # tripping the fail-closed "no JTBD documentation" deny on legitimate edits.
19
+ # Anchor every project-relative check on PROJECT_DIR. Pattern mirrors
20
+ # jtbd-oversight-nudge.sh.
21
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
22
+
13
23
  INPUT=$(cat)
14
24
 
15
25
  FILE_PATH=$(echo "$INPUT" | python3 -c "
@@ -44,7 +54,7 @@ fi
44
54
  case "$FILE_PATH" in
45
55
  /*)
46
56
  case "$FILE_PATH" in
47
- "$PWD"/*) ;;
57
+ "$PROJECT_DIR"/*) ;;
48
58
  *) exit 0 ;;
49
59
  esac
50
60
  ;;
@@ -107,8 +117,8 @@ esac
107
117
  # Legacy docs/JOBS_TO_BE_DONE.md is NOT consulted at runtime; the gate is
108
118
  # inactive on projects that have not run /wr-jtbd:update-guide.
109
119
  JTBD_PATH=""
110
- if [ -d "docs/jtbd" ]; then
111
- JTBD_PATH="docs/jtbd"
120
+ if [ -d "$PROJECT_DIR/docs/jtbd" ]; then
121
+ JTBD_PATH="$PROJECT_DIR/docs/jtbd"
112
122
  fi
113
123
 
114
124
  # If no JTBD docs exist, block and direct to create skill
@@ -7,6 +7,12 @@
7
7
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
8
  source "$SCRIPT_DIR/lib/review-gate.sh"
9
9
 
10
+ # P191: anchor the docs/jtbd detection on the project root, not the hook's
11
+ # runtime CWD (see jtbd-enforce-edit.sh for the full rationale). If this
12
+ # marker-write side false-negatives on docs/jtbd it never stores the marker,
13
+ # and the enforce gate then denies the next edit for lack of a marker.
14
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
15
+
10
16
  INPUT=$(cat)
11
17
 
12
18
  SUBAGENT=$(echo "$INPUT" | jq -r '.tool_input.subagent_type // empty') || true
@@ -19,10 +25,10 @@ fi
19
25
  # Canonical JTBD path — directory only (ADR-008 Option 3). If the
20
26
  # directory doesn't exist the marker is not stored; the gate will
21
27
  # surface a "run update-guide" recommendation on the next edit.
22
- if [ ! -d "docs/jtbd" ]; then
28
+ if [ ! -d "$PROJECT_DIR/docs/jtbd" ]; then
23
29
  exit 0
24
30
  fi
25
- JTBD_PATH="docs/jtbd"
31
+ JTBD_PATH="$PROJECT_DIR/docs/jtbd"
26
32
 
27
33
  case "$SUBAGENT" in
28
34
  *jtbd-lead*|*wr-jtbd*)
@@ -24,3 +24,37 @@ run_hook_with_file() {
24
24
  [ "$status" -eq 0 ]
25
25
  [[ "$output" != *"BLOCKED"* ]]
26
26
  }
27
+
28
+ # P191: the gate must resolve docs/jtbd from the project root
29
+ # (CLAUDE_PROJECT_DIR), NOT the hook's actual runtime CWD. Claude Code can
30
+ # launch the hook with a working directory that differs from the session/
31
+ # project dir; a relative `[ -d "docs/jtbd" ]` then false-negatives and the
32
+ # fail-closed "no JTBD documentation" branch blocks legitimate edits even
33
+ # though docs/jtbd is present.
34
+ @test "jtbd project-root: detects docs/jtbd via CLAUDE_PROJECT_DIR when hook CWD differs (P191)" {
35
+ local proj other json
36
+ proj="$(mktemp -d)"
37
+ other="$(mktemp -d)" # a CWD that does NOT contain docs/jtbd
38
+ mkdir -p "$proj/docs/jtbd"
39
+ echo "# job" > "$proj/docs/jtbd/JTBD-001-x.md"
40
+ json="{\"tool_input\":{\"file_path\":\"${proj}/packages/x/foo.sh\"},\"session_id\":\"test-$$\"}"
41
+ # Fire the hook from `other` (wrong CWD) but with CLAUDE_PROJECT_DIR set to
42
+ # the real project. Pre-fix this emitted "no JTBD documentation exists";
43
+ # post-fix the gate is ACTIVE and denies for the missing review marker.
44
+ run env CLAUDE_PROJECT_DIR="$proj" bash -c "cd '$other' && printf '%s' '$json' | bash '$HOOK'"
45
+ rm -rf "$proj" "$other"
46
+ [[ "$output" != *"no JTBD documentation exists"* ]]
47
+ [[ "$output" == *"without JTBD review"* ]]
48
+ }
49
+
50
+ # P191 regression guard: when docs/jtbd genuinely does not exist under the
51
+ # project root, the fail-closed "no JTBD documentation" deny is preserved
52
+ # (the fix narrows the false-negative; it must not silence true-absence).
53
+ @test "jtbd project-root: genuinely-absent docs/jtbd still denies (fail-closed preserved, P191)" {
54
+ local proj json
55
+ proj="$(mktemp -d)" # no docs/jtbd created
56
+ json="{\"tool_input\":{\"file_path\":\"${proj}/foo.sh\"},\"session_id\":\"test-$$\"}"
57
+ run env CLAUDE_PROJECT_DIR="$proj" bash -c "printf '%s' '$json' | bash '$HOOK'"
58
+ rm -rf "$proj"
59
+ [[ "$output" == *"no JTBD documentation exists"* ]]
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/jtbd",
3
- "version": "0.12.0",
3
+ "version": "0.12.1-preview.562",
4
4
  "description": "Jobs-to-be-done enforcement for UI changes",
5
5
  "bin": {
6
6
  "windyroad-jtbd": "./bin/install.mjs"