@erichll/pi-auto-review 0.8.0 → 0.8.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 +8 -0
- package/README.md +9 -2
- package/package.json +3 -3
- package/src/ui-auto-confirm.ts +37 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.1 - 2026-08-21
|
|
4
|
+
|
|
5
|
+
- Restore TUI auto-confirm for capped `path` / `external_directory` allows on
|
|
6
|
+
permission-system 26.x. `permissions:ui_prompt` no longer carries `message`;
|
|
7
|
+
the bridge now binds `requestId` plus `request.value` (falling back to the
|
|
8
|
+
display `value`, then the legacy `message`) and fingerprints the live dialog
|
|
9
|
+
with those fields. Top-level display `surface` is not treated as the gate.
|
|
10
|
+
|
|
3
11
|
## 0.8.0 - 2026-08-21
|
|
4
12
|
|
|
5
13
|
- Add `/auto-review-approve` for exact non-critical denial retries and remove
|
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ A fail-closed, model-backed boundary reviewer for the Pi coding agent.
|
|
|
4
4
|
|
|
5
5
|
The extension participates in `@gotgenes/pi-permission-system` as the
|
|
6
6
|
`pi-auto-review` authorizer and exposes a process-local broker for OS sandbox
|
|
7
|
-
adapters.
|
|
7
|
+
adapters. It is an authorizer *inside* the permission system, so installing
|
|
8
|
+
that dependency is a hard prerequisite (see [Install and enable](#install-and-enable)). The npm package and reviewer model have separate names:
|
|
8
9
|
|
|
9
10
|
- package: `@erichll/pi-auto-review`
|
|
10
11
|
- authorizer: `pi-auto-review`
|
|
@@ -12,12 +13,18 @@ adapters. The npm package and reviewer model have separate names:
|
|
|
12
13
|
|
|
13
14
|
## Install and enable
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
> **Prerequisite:** pi-auto-review is an authorizer inside
|
|
17
|
+
> `@gotgenes/pi-permission-system`. Pi does not auto-install peer packages, so
|
|
18
|
+
> install the permission system separately (once per machine) before this
|
|
19
|
+
> extension:
|
|
16
20
|
|
|
17
21
|
```bash
|
|
22
|
+
pi install npm:@gotgenes/pi-permission-system
|
|
18
23
|
pi install npm:@erichll/pi-auto-review
|
|
19
24
|
```
|
|
20
25
|
|
|
26
|
+
Install the package outside the agent-writable workspace:
|
|
27
|
+
|
|
21
28
|
Add it to the permission-system authorizer chain:
|
|
22
29
|
|
|
23
30
|
```json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erichll/pi-auto-review",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Model-backed boundary approval broker for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@earendil-works/pi-ai": "^0.84.1",
|
|
51
51
|
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
52
|
-
"@gotgenes/pi-permission-system": "^
|
|
52
|
+
"@gotgenes/pi-permission-system": "^26.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@earendil-works/pi-ai": "^0.84.1",
|
|
56
56
|
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
57
|
-
"@gotgenes/pi-permission-system": "^
|
|
57
|
+
"@gotgenes/pi-permission-system": "^26.0.0",
|
|
58
58
|
"@types/node": "^26.2.0",
|
|
59
59
|
"typescript": "^6.0.3"
|
|
60
60
|
}
|
package/src/ui-auto-confirm.ts
CHANGED
|
@@ -7,9 +7,15 @@ type UiCustom = ExtensionUIContext["custom"];
|
|
|
7
7
|
|
|
8
8
|
type PermissionUiPromptEvent = {
|
|
9
9
|
requestId: string;
|
|
10
|
-
message
|
|
10
|
+
/** Value the live dialog is expected to show (command, path, or legacy message). */
|
|
11
|
+
fingerprint: string;
|
|
12
|
+
/** Gate surface from `request.surface`, when the 26.x payload carries it. */
|
|
13
|
+
gateSurface?: string;
|
|
11
14
|
};
|
|
12
15
|
|
|
16
|
+
/** Prefix length that survives the default 400-char prompt field cap. */
|
|
17
|
+
const FINGERPRINT_PREFIX = 80;
|
|
18
|
+
|
|
13
19
|
type PendingApproval = {
|
|
14
20
|
surface: string;
|
|
15
21
|
expiresAt: number;
|
|
@@ -79,6 +85,9 @@ export class PermissionUiAutoConfirmer {
|
|
|
79
85
|
this.pending.delete(event.requestId);
|
|
80
86
|
|
|
81
87
|
if (!this.enabledSurfaces().includes(pending.surface)) return;
|
|
88
|
+
// Top-level event.surface is the display tool name (e.g. bash), not the
|
|
89
|
+
// gate. Only request.surface is comparable to the staged allow.
|
|
90
|
+
if (event.gateSurface && event.gateSurface !== pending.surface) return;
|
|
82
91
|
this.settleActiveForConflict();
|
|
83
92
|
|
|
84
93
|
const attempt: PromptAttempt = {
|
|
@@ -258,13 +267,24 @@ function parsePermissionUiPromptEvent(
|
|
|
258
267
|
raw: unknown,
|
|
259
268
|
): PermissionUiPromptEvent | undefined {
|
|
260
269
|
if (!isRecord(raw)) return;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
const requestId = nonemptyString(raw.requestId);
|
|
271
|
+
if (!requestId) return;
|
|
272
|
+
|
|
273
|
+
const request = isRecord(raw.request) ? raw.request : undefined;
|
|
274
|
+
// permission-system 26+ removed `message`. Prefer the structured value the
|
|
275
|
+
// dialog actually renders, then the display projection, then the legacy
|
|
276
|
+
// assembled sentence.
|
|
277
|
+
const fingerprint =
|
|
278
|
+
nonemptyString(request?.value) ??
|
|
279
|
+
nonemptyString(raw.value) ??
|
|
280
|
+
nonemptyString(raw.message);
|
|
281
|
+
if (!fingerprint) return;
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
requestId,
|
|
285
|
+
fingerprint,
|
|
286
|
+
gateSurface: nonemptyString(request?.surface),
|
|
287
|
+
};
|
|
268
288
|
}
|
|
269
289
|
|
|
270
290
|
function isPermissionPromptComponent(
|
|
@@ -280,17 +300,23 @@ function isPermissionPromptComponent(
|
|
|
280
300
|
const rendered = value.render(2_000);
|
|
281
301
|
if (!Array.isArray(rendered)) return false;
|
|
282
302
|
const plain = normalizeWhitespace(stripAnsi(rendered.join("\n")));
|
|
283
|
-
const
|
|
303
|
+
const needle = event.fingerprint.slice(0, FINGERPRINT_PREFIX);
|
|
284
304
|
return (
|
|
285
305
|
plain.includes("Permission Required") &&
|
|
286
|
-
|
|
287
|
-
plain.includes(
|
|
306
|
+
needle.length > 0 &&
|
|
307
|
+
plain.includes(needle)
|
|
288
308
|
);
|
|
289
309
|
} catch {
|
|
290
310
|
return false;
|
|
291
311
|
}
|
|
292
312
|
}
|
|
293
313
|
|
|
314
|
+
function nonemptyString(value: unknown): string | undefined {
|
|
315
|
+
if (typeof value !== "string") return;
|
|
316
|
+
const compact = normalizeWhitespace(value);
|
|
317
|
+
return compact || undefined;
|
|
318
|
+
}
|
|
319
|
+
|
|
294
320
|
function invokeUiCustom(
|
|
295
321
|
method: UiCustom,
|
|
296
322
|
ui: ExtensionUIContext,
|