@fyeeme/pi-hooks 1.0.4 → 1.0.5

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/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [1.0.5] - 2026-09-16
11
+
12
+ ### Fixed
13
+
14
+ - A bare exit code 2 with no parseable JSON on stdout is no longer treated as a deny: it is logged as a suspected broken hook command and the tool call proceeds. A crash or misconfiguration (e.g. `python3` exiting 2 for "can't open file") previously hard-blocked every tool call for the rest of the session. Structured JSON denies (`permissionDecision: "deny"`, or exit 2 carrying a deny payload) are unchanged.
15
+
8
16
  ## [1.0.4] - 2026-09-12
9
17
 
10
18
  ### Added
package/README.md CHANGED
@@ -136,7 +136,8 @@ Commands may return JSON on stdout, or control flow via exit codes:
136
136
  ```
137
137
 
138
138
  - exit code **0** with `additionalContext` → context injected.
139
- - exit code **2** (PreToolUse) → tool call blocked (`terminate: true`); reason fed to the model. `terminate` skips the follow-up LLM call only when the denied call is in an all-terminating batch (pi >= 0.84.1, #7715); in a multi-tool batch the block always applies but the agent may continue.
139
+ - exit code **2** (PreToolUse) **with a JSON deny payload** (`permissionDecision: "deny"`) → tool call blocked (`terminate: true`); reason fed to the model. `terminate` skips the follow-up LLM call only when the denied call is in an all-terminating batch (pi >= 0.84.1, #7715); in a multi-tool batch the block always applies but the agent may continue.
140
+ - exit code **2** without parseable JSON (e.g. a broken command like `python3` failing to open a script) → treated as a crash, not a deny: warning on stderr, tool call proceeds. This keeps a misconfigured hook from hard-blocking every tool call.
140
141
  - exit code **2** (Stop) → ignored (pi cannot block exit).
141
142
  - other non-zero → logged, execution continues.
142
143
  - non-JSON stdout → logged as a warning, ignored.
package/index.ts CHANGED
@@ -284,6 +284,18 @@ export function parseHookOutput(command: string, stdout: string, exitCode: numbe
284
284
  }
285
285
  }
286
286
 
287
+ // A bare exit code 2 with no parseable stdout is indistinguishable from a
288
+ // broken hook command (e.g. `python3` exits 2 for "can't open file"), and
289
+ // taking it as a deny hard-blocks EVERY tool call for the rest of the
290
+ // session. Treat the unstructured case as a suspected crash instead: warn
291
+ // and allow. A structured JSON deny still blocks, whatever the exit code.
292
+ if (exitCode === 2 && output === null) {
293
+ console.error(
294
+ `[hooks] exit 2 without a JSON deny payload from ${command} — likely a broken command, not a deny; allowing the call`,
295
+ );
296
+ return { context: null, block: null };
297
+ }
298
+
287
299
  const context = output?.hookSpecificOutput?.additionalContext ?? null;
288
300
  const deny = exitCode === 2 || output?.hookSpecificOutput?.permissionDecision === "deny";
289
301
  const reason =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fyeeme/pi-hooks",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Claude Code-compatible hooks runner for pi. Reads hooks config (priority: ~/.pi/agent/hooks.json, then project .pi/hooks.json) and maps SessionStart, PreToolUse, and Stop events to pi lifecycle events.",
5
5
  "type": "module",
6
6
  "license": "MIT",