agent-control-plane-core 0.2.1 → 0.2.3

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": "agent-control-plane-core",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Vendor-neutral control-plane contract for coding agents: a normalized ToolCallEvent/Verdict schema with per-agent adapters (Claude Code, Codex) and a conformance suite.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -58,6 +58,10 @@ export const MIN_ENFORCING_VERSION = Object.freeze([0, 135]);
58
58
  // Both native events gate a tool call; PermissionRequest is the ask-tier veto.
59
59
  const GATING_EVENTS = new Set(["PreToolUse", "PermissionRequest"]);
60
60
 
61
+ // Codex drops an enforced deny that carries no (or an empty) reason and runs the
62
+ // tool, so a reasonless enforced deny still renders a non-empty one.
63
+ const DEFAULT_DENY_REASON = "blocked by monitor";
64
+
61
65
  const CONSUMED = new Set([
62
66
  "hook_event_name",
63
67
  "session_id",
@@ -163,6 +167,13 @@ export function render(verdict, event, { soleGate = false } = {}) {
163
167
  body.permissionDecision = vd.decision;
164
168
  if (vd.reason !== undefined) body.permissionDecisionReason = vd.reason;
165
169
  }
170
+ // Codex FAILS OPEN on an enforced deny whose permissionDecisionReason is missing
171
+ // or empty: its PreToolUse output parser drops the block (block_reason = None)
172
+ // and runs the tool. Unlike Claude, which honours a bare deny, Codex needs a
173
+ // non-empty reason for the block to bite — so guarantee one on every enforced
174
+ // deny, whatever the judge supplied.
175
+ if (enforced && !body.permissionDecisionReason)
176
+ body.permissionDecisionReason = DEFAULT_DENY_REASON;
166
177
  if (vd.mutated_input !== undefined) body.updatedInput = vd.mutated_input;
167
178
 
168
179
  return nativeResponse({