@mzwing/pi-permission-auto-review 0.1.4 → 0.3.0

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/README.md CHANGED
@@ -10,6 +10,24 @@ A [Pi](https://github.com/earendil-works/pi) extension that adds Codex-style aut
10
10
 
11
11
  Ours is mostly specialized for OpenAI's `codex-auto-review` model, which is trained to evaluate permission requests in the context of a coding assistant. Our extension aims at providing Codex-style automatic permission reviews for Pi's coding agent.
12
12
 
13
+ The bundled baseline is a Pi-specific adaptation of OpenAI Codex Guardian's [`policy_template.md`](https://github.com/openai/codex/blob/c4f42d161ae44a8d696ee9fb595709661979d187/codex-rs/core/src/guardian/policy_template.md) and [`policy.md`](https://github.com/openai/codex/blob/c4f42d161ae44a8d696ee9fb595709661979d187/codex-rs/core/src/guardian/policy.md) at revision [`c4f42d161ae44a8d696ee9fb595709661979d187`](https://github.com/openai/codex/commit/c4f42d161ae44a8d696ee9fb595709661979d187). It is bundled at build time; the extension never fetches policy text while reviewing an action.
14
+
15
+ Upstream's `Execution Environment` section and its MCP `connected_account_email` rule are deliberately left out: both describe Codex's sandbox and tool surface, which Pi's tool-free reviewer does not have. Upstream's `node_repl_policy.md` is likewise out of scope — it governs `node_repl` / `cua_repl` computer-use tools that Pi does not expose.
16
+
17
+ ### Updating the bundled policy
18
+
19
+ `src/upstream.ts` records which Codex files the adaptation tracks and the revision it was last reconciled against. `pnpm sync:policy` reports whether upstream has moved since:
20
+
21
+ ```bash
22
+ pnpm sync:policy # report only; exits non-zero when upstream moved
23
+ pnpm sync:policy --ref v1.2.3 # resolve against a tag, branch, or commit
24
+ pnpm sync:policy --pin # record the new revision, once you have ported it
25
+ ```
26
+
27
+ A run that finds movement lists every commit touching the tracked files since the pinned revision, with links. Port what applies into `src/policy.ts` by hand — the adapted text is a rewrite, not a copy, because Pi's reviewer has no tools and reads a different evidence-provenance model, so upstream wording cannot be dropped in mechanically.
28
+
29
+ Only re-run with `--pin` once that porting is done. `POLICY_REVISION` is written to the permission review log, so a pin that outruns the text would be a false audit record. Bump `PI_ADAPTATION_REVISION` as well when you reword anything Pi-specific. Set `GITHUB_TOKEN` to lift GitHub's anonymous rate limit.
30
+
13
31
  ## Install
14
32
 
15
33
  ```bash
@@ -17,7 +35,9 @@ pi install npm:@gotgenes/pi-permission-system # dependency
17
35
  pi install npm:@mzwing/pi-permission-auto-review
18
36
  ```
19
37
 
20
- Pi 0.80.10 and Pi 0.81.x are supported. The extension uses `@mzwing/pi-polyfill` transitively for provider lookup on Pi 0.80.10; do not install the polyfill as a separate Pi extension.
38
+ Pi 0.84.2+ (0.84.x and 0.85.x) and `@gotgenes/pi-permission-system` 27.x are required.
39
+
40
+ The authorizer registers itself against the service keyed by its own session id, so a subagent's reviewer lands in the node whose gates actually read it.
21
41
 
22
42
  ## Enable
23
43
 
@@ -78,10 +98,42 @@ Custom providers and models must be defined in Pi's `~/.pi/agent/models.json`, t
78
98
 
79
99
  ## Behavior and Limits
80
100
 
101
+ ### Authorization evidence
102
+
103
+ The reviewer reads the current session's complete active branch with `SessionManager.getBranch()`, rather than only the post-compaction model context. This keeps original user authorization available after compaction without mixing in abandoned branches.
104
+
105
+ Only these transcript records can establish authorization:
106
+
107
+ - Pi session user-role messages (`source: "user"`);
108
+ - completed, non-cancelled responses to recognized `ask_user_question` and `plan_mode_question` calls (`source: "user_interaction"`).
109
+
110
+ Pi does not persist the original `input` event source on user-role messages, so `source: "user"` is a trust boundary provided by the Pi runtime rather than cryptographic proof of keyboard input. Trusted extensions can intentionally create such messages with `sendUserMessage()`; as with the rest of Pi's extension model, only trusted extension code should be installed.
111
+
112
+ Structured question responses are accepted only when the non-error result matches a preceding recognized tool call and are rebuilt from `details.answers` data. Free-form tool-result text is never promoted to user evidence. Assistant messages, ordinary tool calls/results, custom messages, and compaction/branch summaries remain untrusted even if their text claims to be user content.
113
+
114
+ Transcript rendering uses separate 10k-token message and tool budgets with per-entry truncation. The first and latest trusted records are retained first, then other trusted records from newest to oldest. The 40-entry recency cap applies only to assistant/tool evidence, so later tool activity cannot evict an already selected user authorization. Truncation indicates missing information; it does not itself raise intrinsic action risk.
115
+
116
+ ### Permission boundaries
117
+
81
118
  - Model, authentication, timeout, provider, or response-format failures defer to the normal human prompt.
82
119
  - Unexpected internal review failures also defer to the human prompt instead of escaping into the permission gate.
83
120
  - Three consecutive denials, or ten denials in the latest fifty reviews, open a circuit breaker until the next Pi turn.
84
- - pi-permission-system prevents authorizers from auto-approving `path` and `external_directory` requests.
121
+ - pi-permission-system's delegation envelope prevents authorizers from auto-approving `path` and `external_directory` requests. An auto-review `allow` for those surfaces is deliberately downgraded to the normal human prompt; this extension does not bypass that boundary.
122
+
123
+ ### Diagnostics
124
+
125
+ Each `auto_review.decision` emitted after transcript construction adds content-free context diagnostics (configuration failures that defer before a review do not have transcript diagnostics):
126
+
127
+ - `policyRevision`
128
+ - `contextSource` (`active-branch`)
129
+ - `transcriptEntriesRetained`
130
+ - `transcriptEntriesOmitted`
131
+ - `transcriptEntriesTruncated`
132
+ - `directUserEntriesRetained` / `directUserEntriesOmitted` / `directUserEntriesTruncated`
133
+ - `userInteractionEntriesRetained` / `userInteractionEntriesOmitted` / `userInteractionEntriesTruncated`
134
+ - `latestTrustedEntryRetained`
135
+
136
+ These fields distinguish missing or truncated authorization evidence from a model decision made after receiving trusted evidence. Transcript text and model rationale are not persisted. The records are written through pi-permission-system's existing permission-review log when that log is enabled.
85
137
 
86
138
  ## License
87
139
 
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ declare const DEFAULT_PROVIDER = "openai-codex";
8
8
  declare const DEFAULT_MODEL = "codex-auto-review";
9
9
  declare const DEFAULT_TIMEOUT_MS = 9e4;
10
10
  declare const CONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/mzwing/pi-packages/main/packages/pi-permission-auto-review/schemas/config.schema.json";
11
+ declare const REASONING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
11
12
  type AutoReviewConfigSchema = z.ZodObject<{
12
13
  $schema: z.ZodOptional<z.ZodString>;
13
14
  additionalPolicy: z.ZodOptional<z.ZodString>;
@@ -27,6 +28,15 @@ type AutoReviewConfigSchema = z.ZodObject<{
27
28
  }, z.core.$strict>;
28
29
  declare const autoReviewConfigSchema: AutoReviewConfigSchema;
29
30
  type AutoReviewConfig = z.infer<typeof autoReviewConfigSchema>;
31
+ interface AutoReviewConfigFile {
32
+ $schema?: string | undefined;
33
+ provider?: string | undefined;
34
+ model?: string | undefined;
35
+ reasoning?: (typeof REASONING_LEVELS)[number] | undefined;
36
+ timeoutMs?: number | undefined;
37
+ includeBaselinePolicy?: boolean | undefined;
38
+ additionalPolicy?: string | undefined;
39
+ }
30
40
  interface ConfigIssue {
31
41
  sourcePath: string;
32
42
  message: string;
@@ -42,6 +52,10 @@ interface LoadConfigOptions {
42
52
  agentDir?: string;
43
53
  readFile?: (path: string) => string | undefined;
44
54
  }
55
+ interface AutoReviewConfigPaths {
56
+ globalPath: string;
57
+ projectPath: string;
58
+ }
45
59
  declare function loadAutoReviewConfig(options: LoadConfigOptions): LoadConfigResult;
46
60
  declare function buildAutoReviewJsonSchema(): Record<string, unknown>;
47
61
  //#endregion
@@ -56,17 +70,68 @@ declare class DenialCircuitBreaker {
56
70
  private recordRecent;
57
71
  }
58
72
  //#endregion
73
+ //#region src/config-store.d.ts
74
+ type AutoReviewConfigScope = "global" | "project";
75
+ interface ScopeSnapshotBase {
76
+ scope: AutoReviewConfigScope;
77
+ cwd: string;
78
+ path: string;
79
+ source: string | undefined;
80
+ }
81
+ type AutoReviewScopeSnapshot = (ScopeSnapshotBase & {
82
+ valid: true;
83
+ config: AutoReviewConfigFile;
84
+ }) | (ScopeSnapshotBase & {
85
+ valid: false;
86
+ issue: ConfigIssue;
87
+ });
88
+ type ConfigMutationResult = {
89
+ ok: true;
90
+ loadResult: LoadConfigResult;
91
+ snapshot: AutoReviewScopeSnapshot;
92
+ } | {
93
+ ok: false;
94
+ message: string;
95
+ };
96
+ interface AutoReviewConfigFileSystem {
97
+ readFile: (path: string) => string | undefined;
98
+ writeFile: (path: string, source: string) => void;
99
+ rename: (sourcePath: string, destinationPath: string) => void;
100
+ mkdir: (path: string) => void;
101
+ unlink: (path: string) => void;
102
+ }
103
+ interface AutoReviewConfigStoreOptions {
104
+ agentDir?: string;
105
+ fileSystem?: AutoReviewConfigFileSystem;
106
+ }
107
+ declare class AutoReviewConfigStore {
108
+ readonly agentDir: string;
109
+ private readonly fileSystem;
110
+ constructor(options?: AutoReviewConfigStoreOptions);
111
+ getPaths(cwd: string): AutoReviewConfigPaths;
112
+ load(cwd: string): LoadConfigResult;
113
+ readScope(cwd: string, scope: AutoReviewConfigScope): AutoReviewScopeSnapshot;
114
+ save(snapshot: AutoReviewScopeSnapshot, draft: AutoReviewConfigFile): ConfigMutationResult;
115
+ reset(snapshot: AutoReviewScopeSnapshot): ConfigMutationResult;
116
+ private loadWithOverride;
117
+ private serialize;
118
+ private checkForConflict;
119
+ private cleanupTempFile;
120
+ }
121
+ //#endregion
59
122
  //#region src/extension.d.ts
60
- interface ReviewerFactoryOptions {
61
- config: AutoReviewConfig;
123
+ interface SessionRuntime {
62
124
  registry: ModelRegistry;
63
- sessionManager: Pick<SessionManager, "buildContextEntries">;
125
+ sessionManager: Pick<SessionManager, "getBranch">;
126
+ }
127
+ interface ReviewerFactoryOptions extends SessionRuntime {
128
+ config: AutoReviewConfig;
64
129
  circuitBreaker: DenialCircuitBreaker;
65
130
  sessionSignal: AbortSignal;
66
131
  }
67
132
  interface AutoReviewExtensionDependencies {
68
- loadConfig?: (cwd: string) => LoadConfigResult;
69
- getPermissionsService?: () => PermissionsService | undefined;
133
+ configStore?: AutoReviewConfigStore;
134
+ getPermissionsService?: (sessionId: string) => PermissionsService | undefined;
70
135
  createReviewer?: (options: ReviewerFactoryOptions) => Authorizer["authorize"];
71
136
  }
72
137
  declare function createAutoReviewExtension(pi: ExtensionAPI, dependencies?: AutoReviewExtensionDependencies): void;
@@ -74,5 +139,5 @@ declare function createAutoReviewExtension(pi: ExtensionAPI, dependencies?: Auto
74
139
  //#region src/index.d.ts
75
140
  declare function permissionAutoReviewExtension(pi: ExtensionAPI): void;
76
141
  //#endregion
77
- export { AUTHORIZER_NAME, type AutoReviewConfig, type AutoReviewExtensionDependencies, CONFIG_SCHEMA_URL, type ConfigIssue, DEFAULT_MODEL, DEFAULT_PROVIDER, DEFAULT_TIMEOUT_MS, EXTENSION_ID, type LoadConfigOptions, type LoadConfigResult, autoReviewConfigSchema, buildAutoReviewJsonSchema, createAutoReviewExtension, permissionAutoReviewExtension as default, loadAutoReviewConfig };
142
+ export { AUTHORIZER_NAME, type AutoReviewConfig, CONFIG_SCHEMA_URL, type ConfigIssue, DEFAULT_MODEL, DEFAULT_PROVIDER, DEFAULT_TIMEOUT_MS, EXTENSION_ID, type LoadConfigOptions, type LoadConfigResult, autoReviewConfigSchema, buildAutoReviewJsonSchema, createAutoReviewExtension, permissionAutoReviewExtension as default, loadAutoReviewConfig };
78
143
  //# sourceMappingURL=index.d.ts.map