@windyroad/risk-scorer 0.16.6 → 0.17.0-preview.945

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.
@@ -310,5 +310,5 @@
310
310
  }
311
311
  },
312
312
  "name": "wr-risk-scorer",
313
- "version": "0.16.6"
313
+ "version": "0.17.0"
314
314
  }
package/hooks/hooks.json CHANGED
@@ -8,10 +8,6 @@
8
8
  { "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/staleness-check.sh" }] }
9
9
  ],
10
10
  "PreToolUse": [
11
- {
12
- "matcher": "Bash|Write|Edit|Read|Glob|Grep|Task|WebFetch|WebSearch",
13
- "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/quota-pace-throttle.sh" }]
14
- },
15
11
  { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/secret-leak-gate.sh" }, { "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/wip-risk-gate.sh" }] },
16
12
  { "matcher": "Bash", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/git-push-gate.sh" }] },
17
13
  { "matcher": "Bash", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-score-commit-gate.sh" }] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/risk-scorer",
3
- "version": "0.16.6",
3
+ "version": "0.17.0-preview.945",
4
4
  "description": "Pipeline risk scoring, commit/push gates, and secret leak detection",
5
5
  "bin": {
6
6
  "windyroad-risk-scorer": "./bin/install.mjs"
@@ -1,104 +0,0 @@
1
- #!/usr/bin/env bash
2
- # quota-pace-throttle.sh — PreToolUse hook (P160 / ADR-093 / RFC-046).
3
- #
4
- # Fires before every tool call across ALL work (interactive + AFK). Mechanically
5
- # paces token burn so it never sprints into a mid-flight quota hard-stop: it
6
- # compares cumulative window usage% against elapsed% and, when AHEAD of pace,
7
- # sleeps the calculated catch-up time (capped per firing). When behind/on pace
8
- # it is a fast no-op. It NEVER blocks, NEVER asks, and fails OPEN on every
9
- # abnormal path — a broken throttle must not break the session.
10
- #
11
- # Data source: ~/.claude/quota-state.json, written by the statusline (the only
12
- # surface Claude Code passes `.rate_limits` to). Fields:
13
- # { "five_used_pct": N, "five_resets_at": <unix>,
14
- # "week_used_pct": N, "week_resets_at": <unix> }
15
- # If the cache is missing/stale/malformed, the hook no-ops (fail-open) — the
16
- # statusline-writer install is a separate, user-consented step.
17
- #
18
- # ponytail: pure arithmetic + one sleep; the 60s/firing cap + fail-open keep the
19
- # blast radius to "at worst a slightly-slower tool call", never a stall or block.
20
-
21
- set +e
22
- CACHE="${WR_QUOTA_CACHE:-${HOME}/.claude/quota-state.json}"
23
- MARKER="${WR_QUOTA_MARKER:-${TMPDIR:-/tmp}/wr-quota-throttle-last}"
24
- FIVE_WINDOW=18000 # 5h in seconds
25
- WEEK_WINDOW=604800 # 7d in seconds
26
- WEEK_HEADROOM_PP=5 # leave 5pp weekly headroom for non-Claude-Code surfaces
27
- CAP_SECONDS=60 # max sleep per firing
28
-
29
- emit_ok() { exit 0; } # PreToolUse: silent allow, never a permissionDecision deny
30
-
31
- # Fail-open preconditions.
32
- command -v jq >/dev/null 2>&1 || emit_ok
33
- [ -r "$CACHE" ] || emit_ok
34
-
35
- now=$(date +%s 2>/dev/null) || emit_ok
36
- case "$now" in ''|*[!0-9]*) emit_ok;; esac
37
-
38
- # Recent-check no-op: if we checked <5s ago, skip recompute (keeps per-call
39
- # latency negligible when we're firing on every tool call).
40
- if [ -f "$MARKER" ]; then
41
- last=$(cat "$MARKER" 2>/dev/null)
42
- case "$last" in
43
- ''|*[!0-9]*) : ;;
44
- *) [ $(( now - last )) -lt 5 ] && emit_ok ;;
45
- esac
46
- fi
47
- printf '%s' "$now" > "$MARKER" 2>/dev/null
48
-
49
- # Read the cache; fail-open on any parse miss.
50
- read -r five_used five_reset week_used week_reset < <(
51
- jq -r '[.five_used_pct, .five_resets_at, .week_used_pct, .week_resets_at]
52
- | map(tostring) | join(" ")' "$CACHE" 2>/dev/null
53
- ) || emit_ok
54
- for v in "$five_used" "$five_reset" "$week_used" "$week_reset"; do
55
- case "$v" in ''|null|*[!0-9.]*) emit_ok;; esac
56
- done
57
-
58
- # elapsed% of a window = (window - remaining) / window * 100, clamped [0,100].
59
- elapsed_pct() { # resets_at window_secs
60
- local remaining=$(( $1 - now )) win="$2" e
61
- [ "$remaining" -lt 0 ] && remaining=0
62
- [ "$remaining" -gt "$win" ] && remaining="$win"
63
- e=$(( (win - remaining) * 100 / win ))
64
- printf '%s' "$e"
65
- }
66
-
67
- # integer-truncate the used% (cache may carry a decimal)
68
- five_used_i=${five_used%%.*}; week_used_i=${week_used%%.*}
69
- five_elapsed=$(elapsed_pct "$five_reset" "$FIVE_WINDOW")
70
- week_elapsed=$(elapsed_pct "$week_reset" "$WEEK_WINDOW")
71
-
72
- # Smart glide-path pacing (P160 refinement 2026-07-06). Rather than a fixed
73
- # catch-up sleep that snaps back to the ideal line, throttle PROPORTIONALLY to
74
- # how far over the glide-path to the window reset we are, easing off as we
75
- # converge — like a runner who is ahead of pace slowing down to drift back,
76
- # not stopping dead. The "safe rate" for the remainder of a window =
77
- # budget-left / time-left (x1000 fixed-point; 1000 = on pace, 0 = budget blown
78
- # with time still on the clock). When safe_rate < 1 we must burn slower, so we
79
- # sleep CAP*(1 - safe_rate). As we slow, wall-clock advances, time-left shrinks,
80
- # safe_rate climbs back toward 1, and the sleep eases to zero exactly as we
81
- # rejoin pace — converging BEFORE the quota is consumed, while still letting
82
- # work through the whole time (never a hard stop; at worst one call per CAP).
83
- safe_rate_x1000() { # used_i elapsed_pct headroom_pp
84
- local budget=$(( 100 - $3 - $1 )) rem=$(( 100 - $2 ))
85
- [ "$rem" -le 0 ] && { printf '1000'; return; } # window reset → unconstrained
86
- [ "$budget" -le 0 ] && { printf '0'; return; } # budget blown → max throttle
87
- printf '%s' $(( budget * 1000 / rem ))
88
- }
89
-
90
- s5=$(safe_rate_x1000 "$five_used_i" "$five_elapsed" 0)
91
- s7=$(safe_rate_x1000 "$week_used_i" "$week_elapsed" "$WEEK_HEADROOM_PP")
92
-
93
- # Tighter window governs = smaller safe_rate.
94
- safe="$s5"; [ "$s7" -lt "$safe" ] && safe="$s7"
95
- [ "$safe" -ge 1000 ] && emit_ok # on/under pace on both windows → fast no-op
96
-
97
- # Proportional ease-back: far over → near CAP (slow, but still one call per CAP);
98
- # slightly over → a short sleep; on pace → zero. The smooth glide, not a stop.
99
- sleep_secs=$(( CAP_SECONDS * (1000 - safe) / 1000 ))
100
- [ "$sleep_secs" -le 0 ] && emit_ok
101
- [ "$sleep_secs" -gt "$CAP_SECONDS" ] && sleep_secs="$CAP_SECONDS"
102
-
103
- sleep "$sleep_secs" 2>/dev/null
104
- emit_ok