@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 +16 -0
- package/README.md +25 -2
- package/package.json +2 -2
- package/src/broker/grants.ts +3 -0
- package/src/broker/types.ts +3 -0
- package/src/index.ts +5 -0
- package/src/integrations/sandbox.ts +18 -0
- package/src/policy.ts +6 -0
- package/src/user-feedback.ts +3 -1
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
|
|
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.
|
|
4
|
-
"description": "
|
|
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": [
|
package/src/broker/grants.ts
CHANGED
|
@@ -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,
|
package/src/broker/types.ts
CHANGED
|
@@ -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,
|
package/src/user-feedback.ts
CHANGED
|
@@ -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 "
|
|
271
|
+
return "warning";
|
|
270
272
|
case "deny":
|
|
271
273
|
case "circuit_breaker":
|
|
272
274
|
return "warning";
|