@rulemetric/hooks 0.12.8 → 0.14.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulemetric/hooks",
3
- "version": "0.12.8",
3
+ "version": "0.14.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -16,6 +16,7 @@
16
16
  "vitest": "^3.2.4"
17
17
  },
18
18
  "scripts": {
19
- "test": "vitest run"
19
+ "test": "vitest run",
20
+ "lint": "eslint ."
20
21
  }
21
22
  }
package/scripts/jq CHANGED
@@ -378,6 +378,14 @@ def run():
378
378
  if files:
379
379
  with open(files[0], "r", encoding="utf-8") as handle:
380
380
  stdin = handle.read()
381
+ elif "n" in flags and not re.search(r"\binputs\b", filter_):
382
+ # Real jq does NOT read stdin under -n/--null-input — its input is
383
+ # null. Reading it anyway made a bare `jq -n --arg k v '{k:$k}'` block
384
+ # forever when the caller attached an open-but-silent stdin (a harness
385
+ # with no heredoc), a divergence invisible in tests that close stdin.
386
+ # `inputs` is the one construct that consumes the stream even under -n
387
+ # and is handled below from this same variable, so it still reads.
388
+ stdin = ""
381
389
  else:
382
390
  stdin = sys.stdin.read()
383
391
 
@@ -95,12 +95,26 @@ _rulemetric_log "session-end" "success"
95
95
  # ── Emit a synthetic instruction snapshot (hooks-first, zero-proxy linking) ──
96
96
  # The proxy classifies the rendered system prompt into context_items that
97
97
  # link-instructions matches on. Hooks-only sessions have no proxy, so build an
98
- # equivalent snapshot from on-disk CLAUDE.md files and POST it SYNCHRONOUSLY —
99
- # it must land before the backgrounded link-instructions call below. Best-effort:
100
- # a failure never breaks session-end (see the ERR trap guard). Claude Code only
101
- # for now (the snapshot uses claude_md items).
102
- if [ "$HOOK_TOOL" = "claude_code" ]; then
103
- INSTR_SNAPSHOT=$(rulemetric hooks emit-instructions --project-dir "${HOOK_CWD:-$(pwd)}" 2>/dev/null || true)
98
+ # equivalent snapshot from the on-disk instruction files and POST it
99
+ # SYNCHRONOUSLY — it must land before the backgrounded link-instructions call
100
+ # below. Best-effort: a failure never breaks session-end (see the ERR trap guard).
101
+ #
102
+ # The tool is PASSED, not assumed: each harness reads a different file
103
+ # (CLAUDE.md / AGENTS.md / .github/copilot-instructions.md). This block used to
104
+ # be gated on claude_code alone, so a Codex or Copilot project could have a rule
105
+ # adopted into the file its agent reads while linking never saw it. The command
106
+ # prints nothing for a tool it does not know, so an unrecognised HOOK_TOOL is a
107
+ # no-op rather than a CLAUDE.md attributed to the wrong harness.
108
+ #
109
+ # Kept in its OWN variable: HOOK_TOOL is still read further down (the transcript
110
+ # reimport is claude_code-only), so narrowing it here would silently disable
111
+ # that block too.
112
+ case "$HOOK_TOOL" in
113
+ claude_code|codex|copilot_agent|copilot_cli|vscode_copilot) SNAPSHOT_TOOL="$HOOK_TOOL" ;;
114
+ *) SNAPSHOT_TOOL="" ;;
115
+ esac
116
+ if [ -n "$SNAPSHOT_TOOL" ]; then
117
+ INSTR_SNAPSHOT=$(rulemetric hooks emit-instructions --project-dir "${HOOK_CWD:-$(pwd)}" --tool "$SNAPSHOT_TOOL" 2>/dev/null || true)
104
118
  if [ -n "$INSTR_SNAPSHOT" ]; then
105
119
  # Bounded 503/429 retry — this snapshot is the ONLY instruction-linking
106
120
  # signal a hooks-only (no-proxy) session ever emits; a one-shot curl made