@erichll/pi-auto-review 0.10.0 → 0.11.1

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
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.1 - 2026-08-25
4
+
5
+ - Align the package version with `@erichll/pi-sandbox` `0.11.1`. No
6
+ pi-auto-review runtime or public API changes.
7
+
8
+ ## 0.11.0 - 2026-08-24
9
+
10
+ - **Structured network destination.** Network approval requests now carry
11
+ separate host, port, and protocol fields alongside the existing combined
12
+ destination string. One-shot grants bind each component independently, so a
13
+ grant issued for one host-port-protocol combination cannot be reused for a
14
+ different one.
15
+ - **Deferred reviews are more visible.** The review widget now highlights
16
+ deferred verdicts with a warning accent instead of the previous muted style,
17
+ making pending human decisions easier to spot.
18
+
3
19
  ## 0.10.0 - 2026-08-22
4
20
 
5
21
  - Replace the review footer and newly appended transcript entries with one
package/README.md CHANGED
@@ -11,6 +11,20 @@ that dependency is a hard prerequisite (see [Install and enable](#install-and-en
11
11
  - authorizer: `pi-auto-review`
12
12
  - default reviewer model: `codex-auto-review`
13
13
 
14
+ ## Contents
15
+
16
+ - [Install and enable](#install-and-enable)
17
+ - [Security model](#security-model)
18
+ - [Configuration](#configuration)
19
+ - [Deadlines and retries](#deadlines-and-retries)
20
+ - [Operator feedback and exact retry](#operator-feedback-and-exact-retry)
21
+ - [Boundary broker API](#boundary-broker-api)
22
+ - [Reviewer context and token budgets](#reviewer-context-and-token-budgets)
23
+ - [Sandbox integration](#sandbox-integration)
24
+ - [Trust boundary](#trust-boundary)
25
+ - [Telemetry](#telemetry)
26
+ - [Real-model smoke test](#real-model-smoke-test)
27
+
14
28
  ## Install and enable
15
29
 
16
30
  > **Prerequisite:** pi-auto-review is an authorizer inside
@@ -23,7 +37,8 @@ pi install npm:@gotgenes/pi-permission-system
23
37
  pi install npm:@erichll/pi-auto-review
24
38
  ```
25
39
 
26
- Install the package outside the agent-writable workspace:
40
+ Install the package outside the agent-writable workspace (see
41
+ [Trust boundary](#trust-boundary)):
27
42
 
28
43
  Add it to the permission-system authorizer chain:
29
44
 
@@ -85,6 +100,12 @@ Use the user-global file for normal customization. It may set any legal key:
85
100
  }
86
101
  ```
87
102
 
103
+ For a complete `@gotgenes/pi-permission-system` config that wires
104
+ `pi-auto-review` into the authorizer chain — a copyable baseline covering
105
+ read/write/edit, a read-only bash allowlist, an MCP discovery policy, and a
106
+ `path` deny block for secret and credential files — see
107
+ [`examples/pi-permission-system.config.example.json`](examples/pi-permission-system.config.example.json).
108
+
88
109
  Package defaults:
89
110
 
90
111
  ```json
@@ -292,7 +313,7 @@ Writes to the installed reviewer package, its user-global configuration,
292
313
  project and global security configuration, and the global audit directory are
293
314
  deterministically denied.
294
315
 
295
- ## Telemetry and smoke testing
316
+ ## Telemetry
296
317
 
297
318
  Every actual model call emits an internal `review_attempt`; each approval emits
298
319
  one `review_complete`. Events contain stable status/error classes, timings,
@@ -301,6 +322,8 @@ prompt or response text, provider errors, credentials, headers, or URL query
301
322
  values. Usage is marked `unknown_provenance` when pi-ai cannot distinguish
302
323
  provider counters from initialized values, and `unavailable` when absent.
303
324
 
325
+ ## Real-model smoke test
326
+
304
327
  For a controlled real-model smoke test, load only the provider, reviewer,
305
328
  sandbox, and audit listener:
306
329
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erichll/pi-auto-review",
3
- "version": "0.10.0",
4
- "description": "Model-backed boundary approval broker for Pi",
3
+ "version": "0.11.1",
4
+ "description": "Fail-closed, model-backed approval broker for Pi: deterministically hard-denies dangerous operations, reviews dangerous boundaries with a reviewer model, and issues one-shot expiring grants that OS sandbox adapters must consume before retrying.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -22,6 +22,9 @@ export function boundaryRequestHash(request: BoundaryRequest): string {
22
22
  path: request.path,
23
23
  resolvedPath: request.resolvedPath,
24
24
  destination: request.destination,
25
+ destinationHost: request.destinationHost,
26
+ destinationPort: request.destinationPort,
27
+ destinationProtocol: request.destinationProtocol,
25
28
  toolCallId: request.toolCallId,
26
29
  toolName: request.toolName,
27
30
  skillName: request.skillName,
@@ -22,6 +22,9 @@ export type BoundaryRequest = {
22
22
  path?: string;
23
23
  resolvedPath?: string;
24
24
  destination?: string;
25
+ destinationHost?: string;
26
+ destinationPort?: number;
27
+ destinationProtocol?: string;
25
28
  toolCallId?: string;
26
29
  toolName?: string;
27
30
  skillName?: string;
package/src/index.ts CHANGED
@@ -64,6 +64,8 @@ export {
64
64
  type SandboxNetworkTrap,
65
65
  type SandboxRequestContext,
66
66
  } from "./integrations/sandbox.ts";
67
+ import { parseHostPort } from "./integrations/sandbox.ts";
68
+ export { parseHostPort };
67
69
 
68
70
  type ReasoningLevel =
69
71
  | "off"
@@ -749,6 +751,7 @@ function boundaryRequest(
749
751
  typeof deterministicPolicy === "string"
750
752
  ? deterministicPolicy
751
753
  : JSON.stringify(deterministicPolicy);
754
+ const destParsed = parseHostPort(evidence.destination);
752
755
  return {
753
756
  id: details.requestId,
754
757
  source: "permission-system",
@@ -759,6 +762,8 @@ function boundaryRequest(
759
762
  path: evidence.path,
760
763
  resolvedPath: evidence.resolvedPath,
761
764
  destination: evidence.destination,
765
+ destinationHost: destParsed?.host,
766
+ destinationPort: destParsed?.port,
762
767
  toolCallId:
763
768
  typeof (details as unknown as Record<string, unknown>).toolCallId ===
764
769
  "string"
@@ -36,6 +36,21 @@ export type SandboxRequestContext = {
36
36
  agentName?: string;
37
37
  };
38
38
 
39
+ export function parseHostPort(target: string | undefined): {
40
+ host: string;
41
+ port: number | undefined;
42
+ } | undefined {
43
+ if (!target) return undefined;
44
+ const lastColon = target.lastIndexOf(":");
45
+ if (lastColon <= 0) return { host: target, port: undefined };
46
+ const portStr = target.slice(lastColon + 1);
47
+ const port = Number(portStr);
48
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
49
+ return { host: target, port: undefined };
50
+ }
51
+ return { host: target.slice(0, lastColon), port };
52
+ }
53
+
39
54
  export function sandboxTrapToBoundaryRequest(
40
55
  trap: SandboxBoundaryTrap,
41
56
  context: SandboxRequestContext,
@@ -66,6 +81,7 @@ export function sandboxTrapToBoundaryRequest(
66
81
  },
67
82
  };
68
83
  }
84
+ const parsed = parseHostPort(trap.target);
69
85
  return {
70
86
  id,
71
87
  source: "sandbox-runtime",
@@ -74,6 +90,8 @@ export function sandboxTrapToBoundaryRequest(
74
90
  cwd: trap.process?.cwd || context.cwd,
75
91
  command: context.command,
76
92
  destination: trap.target,
93
+ destinationHost: parsed?.host,
94
+ destinationPort: parsed?.port,
77
95
  toolName: trap.process?.exe || undefined,
78
96
  agentName: context.agentName,
79
97
  matchedPolicy: { decision: "ask" },
package/src/policy.ts CHANGED
@@ -156,6 +156,9 @@ export type RelevantBoundaryRequest = {
156
156
  path?: string;
157
157
  resolvedPath?: string;
158
158
  destination?: string;
159
+ destinationHost?: string;
160
+ destinationPort?: number;
161
+ destinationProtocol?: string;
159
162
  toolCallId?: string;
160
163
  toolName?: string;
161
164
  toolInputPreview?: string;
@@ -1098,6 +1101,9 @@ function toolArgumentCoveredByRequest(
1098
1101
  path: request.path,
1099
1102
  resolvedPath: request.resolvedPath,
1100
1103
  destination: request.destination,
1104
+ destinationHost: request.destinationHost,
1105
+ destinationPort: request.destinationPort,
1106
+ destinationProtocol: request.destinationProtocol,
1101
1107
  cwd: request.cwd,
1102
1108
  agentName: request.agentName,
1103
1109
  requesterSessionId: request.requesterSessionId,
@@ -265,8 +265,10 @@ function outcomeAccent(
265
265
  case "auto_confirm":
266
266
  case "needs_confirmation":
267
267
  return "success";
268
+ // Deferred also warns: it awaits a human decision, so it must be clearly
269
+ // visible (theme warning) and stand out until resolved.
268
270
  case "defer":
269
- return "muted";
271
+ return "warning";
270
272
  case "deny":
271
273
  case "circuit_breaker":
272
274
  return "warning";