@windyroad/jtbd 0.14.12 → 0.15.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.
@@ -90,5 +90,5 @@
90
90
  }
91
91
  },
92
92
  "name": "wr-jtbd",
93
- "version": "0.14.12"
93
+ "version": "0.15.0"
94
94
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wr-jtbd",
3
- "version": "0.14.12",
3
+ "version": "0.15.0",
4
4
  "description": "Jobs-to-be-done governance for product changes",
5
5
  "author": {
6
6
  "name": "Windy Road Technology",
@@ -154,6 +154,9 @@ _HOOK_INPUT=""
154
154
 
155
155
  _parse_input() {
156
156
  _HOOK_INPUT=$(cat)
157
+ if ! printf '%s' "$_HOOK_INPUT" | python3 -c 'import json,sys; assert isinstance(json.load(sys.stdin),dict)' 2>/dev/null; then
158
+ _governance_advisory "Hook input could not be parsed."
159
+ fi
157
160
  }
158
161
 
159
162
  _get_tool_name() {
@@ -327,3 +330,8 @@ _is_doc_file() {
327
330
  esac
328
331
  return 1
329
332
  }
333
+
334
+ # Mechanical evaluation failures are advisory; never mint approval receipts.
335
+ _governance_advisory() {
336
+ python3 -c 'import json,sys; print(json.dumps({"systemMessage": "Governance evidence unavailable; action permitted. " + sys.argv[1]}))' "$1" || echo 'Governance evidence unavailable; action permitted.' >&2
337
+ }
@@ -7,10 +7,10 @@
7
7
  _REVIEW_GATE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
8
  source "$_REVIEW_GATE_DIR/gate-helpers.sh"
9
9
 
10
- # Check review gate marker. Returns 0 if marker is valid (allow), 1 if invalid (deny).
10
+ # Validate review receipt; the public gate below converts unavailable evidence to an advisory.
11
11
  # Sets REVIEW_GATE_REASON on failure.
12
12
  # Usage: check_review_gate "$SESSION_ID" "style-guide" "docs/STYLE-GUIDE.md"
13
- check_review_gate() {
13
+ _check_review_receipt() {
14
14
  local SESSION_ID="$1"
15
15
  local SYSTEM="$2" # e.g., "a11y", "voice-tone", "style-guide"
16
16
  local POLICY_FILE="$3" # e.g., "docs/STYLE-GUIDE.md"
@@ -82,24 +82,21 @@ store_review_hash() {
82
82
  return 0
83
83
  }
84
84
 
85
- # Emit fail-closed deny JSON for PreToolUse hooks.
85
+ # Emit an advisory for unverifiable review requirements.
86
86
  review_gate_deny() {
87
- local REASON="$1"
88
- cat <<EOF
89
- {
90
- "hookSpecificOutput": {
91
- "hookEventName": "PreToolUse",
92
- "permissionDecision": "deny",
93
- "permissionDecisionReason": "$REASON"
94
- }
95
- }
96
- EOF
87
+ _governance_advisory "$1"
97
88
  }
98
89
 
99
- # Emit fail-closed deny JSON for parse failures.
90
+ # Permit parsing failures with an unavailable-evidence advisory.
100
91
  review_gate_parse_error() {
101
92
  cat <<'EOF'
102
- { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny",
103
- "permissionDecisionReason": "BLOCKED: Could not parse hook input. Gate is fail-closed." } }
93
+ { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow",
94
+ "permissionDecisionReason": "Governance evidence unavailable: could not parse hook input; action permitted." } }
104
95
  EOF
105
96
  }
97
+
98
+ check_review_gate() {
99
+ if _check_review_receipt "$@"; then return 0; fi
100
+ _governance_advisory "$REVIEW_GATE_REASON"
101
+ return 0
102
+ }
@@ -5,8 +5,34 @@ target="$1"
5
5
  input="$(cat)"
6
6
  tool="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
7
7
 
8
+ ADVISORIES=""
9
+ collect_gate_output() {
10
+ local output="$1" parsed
11
+ [ -n "$output" ] || return 0
12
+ if ! parsed="$(printf '%s' "$output" | jq -cs '
13
+ if any(.[]; .hookSpecificOutput.permissionDecision == "deny")
14
+ then map(select(.hookSpecificOutput.permissionDecision == "deny"))[0]
15
+ else {systemMessage: map(.systemMessage // .hookSpecificOutput.permissionDecisionReason // "Governance evidence unavailable; action permitted.") | join("\n")} end' 2>/dev/null)"; then
16
+ parsed='{"systemMessage":"Governance evidence unavailable: malformed evaluator output; action permitted."}'
17
+ fi
18
+ if printf '%s' "$parsed" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
19
+ printf '%s\n' "$parsed"
20
+ exit 0
21
+ fi
22
+ ADVISORIES="$ADVISORIES
23
+ $parsed"
24
+ }
25
+ flush_advisories() {
26
+ [ -n "$ADVISORIES" ] || return 0
27
+ printf '%s' "$ADVISORIES" | jq -s '{systemMessage: map(.systemMessage // .hookSpecificOutput.permissionDecisionReason // "Governance evidence unavailable; action permitted.") | join("\n")}'
28
+ }
8
29
  run_hook() {
9
- printf '%s' "$1" | "$target"
30
+ local output
31
+ if ! output="$(printf '%s' "$1" | "$target" 2>/dev/null)"; then
32
+ collect_gate_output '{"systemMessage":"Governance evaluator unavailable; action permitted. A crashed hook output was discarded."}'
33
+ return 0
34
+ fi
35
+ collect_gate_output "$output"
10
36
  }
11
37
 
12
38
  if [ "$tool" = "apply_patch" ]; then
@@ -16,6 +42,7 @@ if [ "$tool" = "apply_patch" ]; then
16
42
  payload="$(printf '%s' "$input" | jq --arg path "$path" '.tool_name = "Edit" | .tool_input.file_path = $path')"
17
43
  run_hook "$payload" || exit $?
18
44
  done <<< "$paths"
45
+ flush_advisories
19
46
  exit 0
20
47
  fi
21
48
  fi
@@ -25,3 +52,4 @@ if [ "$tool" = "spawn_agent" ] || [ "$tool" = "Agent" ]; then
25
52
  fi
26
53
 
27
54
  run_hook "$input"
55
+ flush_advisories
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/jtbd",
3
- "version": "0.14.12",
3
+ "version": "0.15.0",
4
4
  "description": "Jobs-to-be-done enforcement for UI changes",
5
5
  "bin": {
6
6
  "windyroad-jtbd": "./bin/install.mjs"