@hank-warren/pi-auto-permissions 0.8.0 → 0.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @hank-warren/pi-auto-permissions
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0e9400e: Remove the built-in `openai-codex-auto-permissions` provider. Additional logins are now the job of `@hank-warren/pi-multi-login`, which adopts the existing credential on first run, so an existing `reviewer.provider` config keeps resolving with no edit.
8
+
9
+ Without that package installed the reviewer provider is missing; session start now warns once naming the provider instead of leaving the first guarded command to fail with a bare "review model not found".
10
+
11
+ ## 0.9.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 7d96995: Stop `pi-herdr-auto-title` depending on `pi-auto-permissions`.
16
+
17
+ The pane-title extension deep-imported `guardian-transport.ts` — roughly forty lines resolving `completeSimple` through the host `ModelRuntime` so provider extensions (Anthropic OAuth shaping) apply to background model calls. Reusing it cost an entire dependency on the permissions engine: 125 kB unpacked in `node_modules`, a transitive `pi-permission-selector`, and a no-op release of the title extension every time the guardian shipped.
18
+
19
+ The file is now duplicated byte-for-byte into both packages, and `scripts/validate.py` fails if the copies drift. `pi-herdr-auto-title` declares no dependencies at all and its tarball is unchanged apart from the added source file.
20
+
21
+ To keep the copies identical, `resolveGuardianCompleteSimple` takes the calling package's name as a second argument and uses it in the compat-fallback warning, replacing the hardcoded `[pi-auto-permissions]` prefix. That is a breaking change only for an external deep import of `@hank-warren/pi-auto-permissions/guardian-transport.ts`; the extension's own behavior is unchanged.
22
+
23
+ ### Patch Changes
24
+
25
+ - 7d96995: Make every declared dependency accurate.
26
+
27
+ `pi-permission-selector` no longer declares a `@earendil-works/pi-coding-agent` peer dependency. It imports nothing from it — the claim was left over from 1.0.0, which removed the extension and the selector monkey patch and turned the package into a pure library.
28
+
29
+ `pi-auto-permissions` floors `@hank-warren/pi-permission-selector` at `^1.1.0` and `pi-plan-mode` floors `@narumitw/pi-tui-kit` at `^0.49.3`, in both cases the lowest version the package is actually tested against. Neither uses a feature the old floor lacked, so nothing changes at install time under caret resolution; the ranges simply no longer claim support that nothing verifies.
30
+
31
+ `scripts/validate.py` now enforces that a package's Pi `peerDependencies` are exactly the Pi packages its shipped sources import, in both directions.
32
+
33
+ - Updated dependencies [7d96995]
34
+ - @hank-warren/pi-permission-selector@1.1.1
35
+
3
36
  ## 0.8.0
4
37
 
5
38
  ### Minor Changes
package/README.md CHANGED
@@ -116,10 +116,10 @@ Set `enabled` to `false` to disable the extension. Invalid configuration fails c
116
116
 
117
117
  By default, the guardian uses Pi's active model with low reasoning effort and a 30-second timeout. You can select a separate low-cost model.
118
118
 
119
- For OpenAI Codex, this package registers a second provider named **OpenAI Codex - Auto Permissions**. Pi keys OAuth credentials by provider id, so this provider can use a different ChatGPT account without replacing the normal `openai-codex` login used by your main agent.
119
+ Giving the guardian its own account keeps reviews from competing with your interactive session for a subscription's rate limits. Pi keys OAuth credentials by provider id, so a second login needs a second provider id — which is what [`@hank-warren/pi-multi-login`](../pi-multi-login/README.md) exists to create. This package no longer registers one itself.
120
120
 
121
- 1. Run `/login` and select **OpenAI Codex - Auto Permissions**.
122
- 2. Complete OAuth with the account reserved for guardian reviews.
121
+ 1. `pi install npm:@hank-warren/pi-multi-login`
122
+ 2. Run `/multi-login`, add a login with base `openai-codex` and suffix `auto-permissions`, and complete OAuth with the account reserved for guardian reviews.
123
123
  3. Select the dedicated provider in the Auto Permissions config:
124
124
 
125
125
  ```json
@@ -133,7 +133,9 @@ For OpenAI Codex, this package registers a second provider named **OpenAI Codex
133
133
  }
134
134
  ```
135
135
 
136
- The separate credential is stored in Pi's normal `auth.json` under `openai-codex-auto-permissions`; the existing `openai-codex` credential is unchanged. The alias uses Pi's built-in OpenAI Codex OAuth flow, model catalog, and transport. Because it is a normal provider, its models also appear under the dedicated provider name in Pi's model selector after login.
136
+ The separate credential is stored in Pi's normal `auth.json` under `openai-codex-auto-permissions`; the existing `openai-codex` credential is unchanged. The alias uses Pi's built-in OpenAI Codex OAuth flow, model catalog, and transport. Because it is a normal provider, its models also appear in Pi's model selector and in `/login` after login.
137
+
138
+ If you already used the login this package registered in earlier versions, nothing changes: `pi-multi-login` adopts the existing `openai-codex-auto-permissions` credential on first run, so the config above keeps resolving. Without that package installed, the provider is missing and Auto Permissions warns once per session; point `reviewer.provider` at `openai-codex` (or any signed-in provider) to silence it.
137
139
 
138
140
  Other reviewer providers continue to work by setting their normal provider and model ids.
139
141
 
@@ -1,17 +1,17 @@
1
1
  import { completeSimple } from "@earendil-works/pi-ai/compat";
2
2
 
3
3
  /**
4
- * Guardian model dispatch seam.
4
+ * Model dispatch seam for extension-issued background model calls.
5
5
  *
6
6
  * pi-ai's `compat.completeSimple` dispatches through pi-ai's own api registry,
7
7
  * which extension-registered provider transports never reach: pi routes
8
8
  * `pi.registerProvider()` configs only through the coding agent's
9
9
  * `ModelRuntime` -> `provider-composer.streamWith`. Auth-shaping extensions
10
10
  * such as `@gotgenes/pi-anthropic-auth` install their transport wrapper there,
11
- * so a reviewer request issued via `compat.completeSimple` reaches Anthropic
12
- * unshaped, and Claude Pro/Max OAuth requests fail with the misleading
13
- * "extra usage" HTTP 400 (see gotgenes/pi-anthropic-auth
14
- * docs/architecture.md, "The remaining gap: pi-ai compat dispatch").
11
+ * so a request issued via `compat.completeSimple` reaches Anthropic unshaped,
12
+ * and Claude Pro/Max OAuth requests fail with the misleading "extra usage"
13
+ * HTTP 400 (see gotgenes/pi-anthropic-auth docs/architecture.md, "The
14
+ * remaining gap: pi-ai compat dispatch").
15
15
  *
16
16
  * `ExtensionContext.modelRegistry` is a deliberately narrowed facade over
17
17
  * `ModelRuntime` that re-exports `complete()` but not `completeSimple()` —
@@ -21,12 +21,24 @@ import { completeSimple } from "@earendil-works/pi-ai/compat";
21
21
  * marked `private` in the .d.ts), and fall back to compat dispatch when a
22
22
  * future pi release renames the seam — degrading to the historical behavior
23
23
  * instead of crashing.
24
+ *
25
+ * THIS FILE IS DUPLICATED VERBATIM across packages/pi-auto-permissions and
26
+ * packages/pi-herdr-auto-title, and `scripts/validate.py` fails if the copies
27
+ * differ by a single byte. The duplication is deliberate: sharing it made a
28
+ * pane-titling extension depend on an entire permissions engine to reuse a
29
+ * dozen lines. Edit one copy, then copy it over the other. Every
30
+ * package-specific detail must stay behind a parameter — hence `packageLabel`.
31
+ * The "guardian" in the names is historical: pi-auto-permissions' guardian
32
+ * reviewer was the first caller.
24
33
  */
25
34
  export type GuardianCompleteSimple = typeof completeSimple;
26
35
 
27
36
  let warnedCompatFallback = false;
28
37
 
29
- export function resolveGuardianCompleteSimple(modelRegistry: unknown): GuardianCompleteSimple {
38
+ export function resolveGuardianCompleteSimple(
39
+ modelRegistry: unknown,
40
+ packageLabel: string,
41
+ ): GuardianCompleteSimple {
30
42
  const runtime = (modelRegistry as { runtime?: unknown } | null | undefined)?.runtime;
31
43
  const candidate = (runtime as { completeSimple?: unknown } | null | undefined)?.completeSimple;
32
44
  if (typeof candidate === "function") {
@@ -35,7 +47,7 @@ export function resolveGuardianCompleteSimple(modelRegistry: unknown): GuardianC
35
47
  if (!warnedCompatFallback) {
36
48
  warnedCompatFallback = true;
37
49
  console.warn(
38
- "[pi-auto-permissions] host ModelRuntime completeSimple is unavailable; falling back to pi-ai compat dispatch. Extension-registered provider transports (e.g. Anthropic OAuth shaping) will not apply to reviewer calls.",
50
+ `[${packageLabel}] host ModelRuntime completeSimple is unavailable; falling back to pi-ai compat dispatch. Extension-registered provider transports (e.g. Anthropic OAuth shaping) will not apply to this extension's model calls.`,
39
51
  );
40
52
  }
41
53
  return completeSimple;
package/index.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { cleanupSessionResources, type Message } from "@earendil-works/pi-ai";
2
2
  import { resolveGuardianCompleteSimple } from "./guardian-transport.js";
3
- import {
4
- createAutoPermissionsOpenAICodexProvider,
5
- isOpenAICodexModel,
6
- } from "./openai-codex-provider.js";
3
+ import { isOpenAICodexModel } from "./openai-codex-transport.js";
7
4
  import { detectSubagentContext } from "./subagent-context.js";
8
5
  import * as PiCodingAgent from "@earendil-works/pi-coding-agent";
9
6
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
@@ -272,6 +269,29 @@ export default function autoPermissionsExtension(pi: ExtensionAPI) {
272
269
  }
273
270
  }
274
271
 
272
+ /**
273
+ * The dedicated `openai-codex-auto-permissions` login used to be registered
274
+ * here. It now belongs to @hank-warren/pi-multi-login, which adopts the
275
+ * existing credential, so an existing reviewer config keeps working — but only
276
+ * if that package is installed. Say so once per session instead of letting the
277
+ * first guarded command fail with a bare "review model not found".
278
+ */
279
+ function warnAboutMissingReviewerProvider(ctx: ExtensionContext): void {
280
+ let provider: string | undefined;
281
+ try {
282
+ provider = currentConfig(ctx).reviewer?.provider;
283
+ } catch {
284
+ return; // The config error was already reported by currentConfig().
285
+ }
286
+ if (!provider || ctx.modelRegistry.getProvider(provider)) return;
287
+
288
+ const message =
289
+ `reviewer provider "${provider}" is not registered. Install @hank-warren/pi-multi-login to` +
290
+ ` provide additional logins such as this one, or point reviewer.provider at a signed-in provider.`;
291
+ console.warn(`[pi-auto-permissions] ${message}`);
292
+ ctx.ui.notify(`Auto Permissions: ${message}`, "warning");
293
+ }
294
+
275
295
  async function reviewCommand(
276
296
  gate: Gate,
277
297
  toolName: string,
@@ -383,7 +403,7 @@ export default function autoPermissionsExtension(pi: ExtensionAPI) {
383
403
  }
384
404
  // Dispatch through the host ModelRuntime so extension-registered provider
385
405
  // transports (e.g. pi-anthropic-auth OAuth shaping) apply; see guardian-transport.ts.
386
- const response = await resolveGuardianCompleteSimple(ctx.modelRegistry)(
406
+ const response = await resolveGuardianCompleteSimple(ctx.modelRegistry, "pi-auto-permissions")(
387
407
  model,
388
408
  { systemPrompt, messages },
389
409
  {
@@ -997,12 +1017,7 @@ export default function autoPermissionsExtension(pi: ExtensionAPI) {
997
1017
  });
998
1018
 
999
1019
  pi.on("session_start", async (_event, ctx) => {
1000
- const openaiCodex = ctx.modelRegistry.getProvider("openai-codex");
1001
- if (openaiCodex?.auth.oauth) {
1002
- pi.registerProvider(createAutoPermissionsOpenAICodexProvider(openaiCodex));
1003
- } else {
1004
- console.warn("[pi-auto-permissions] OpenAI Codex OAuth is unavailable; the dedicated Auto Permissions login was not registered.");
1005
- }
1020
+ warnAboutMissingReviewerProvider(ctx);
1006
1021
 
1007
1022
  reviewerLifecycleController.abort();
1008
1023
  discardReviewerLineage();
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Codex models are reached over a websocket session rather than plain HTTP, and
3
+ * the guardian has to pick that transport itself. The check is on the model's
4
+ * api rather than its provider id so it keeps working for a reviewer pointed at
5
+ * an aliased Codex login (see @hank-warren/pi-multi-login).
6
+ */
7
+ export function isOpenAICodexModel(model: { api?: string }): boolean {
8
+ return model.api === "openai-codex-responses";
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hank-warren/pi-auto-permissions",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Fork of @ogulcancelik/pi-auto-permissions with dialog-answer user evidence: context-aware Bash permissions for Pi with automated guardian review.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "approval-pulse.ts",
43
43
  "config.ts",
44
44
  "guardian-transport.ts",
45
- "openai-codex-provider.ts",
45
+ "openai-codex-transport.ts",
46
46
  "subagent-context.ts",
47
47
  "evaluation-log.ts",
48
48
  "gates.ts",
@@ -55,7 +55,7 @@
55
55
  "CHANGELOG.md"
56
56
  ],
57
57
  "dependencies": {
58
- "@hank-warren/pi-permission-selector": "^1.0.1"
58
+ "@hank-warren/pi-permission-selector": "^1.1.1"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@earendil-works/pi-ai": "*",
@@ -1,42 +0,0 @@
1
- import type { Provider } from "@earendil-works/pi-ai";
2
-
3
- export const AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_ID = "openai-codex-auto-permissions";
4
- export const AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_NAME = "OpenAI Codex - Auto Permissions";
5
-
6
- /**
7
- * Registering a second provider id gives Pi a second auth.json credential slot.
8
- * The transport and model catalog still come from Pi's built-in OpenAI Codex
9
- * provider, so the alias follows the host Pi version instead of duplicating its
10
- * OAuth or Responses implementation here. The effective catalog is snapshotted
11
- * when the session starts; the source provider remains the sole owner of any
12
- * dynamic catalog refresh state.
13
- */
14
- export function createAutoPermissionsOpenAICodexProvider(source: Provider): Provider {
15
- const models = source.getModels().map((model) => ({
16
- ...model,
17
- provider: AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_ID,
18
- }));
19
- const oauth = source.auth.oauth;
20
-
21
- if (!oauth) {
22
- throw new Error("Pi's OpenAI Codex provider does not expose OAuth authentication");
23
- }
24
-
25
- return {
26
- ...source,
27
- id: AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_ID,
28
- name: AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_NAME,
29
- auth: {
30
- oauth: {
31
- ...oauth,
32
- name: AUTO_PERMISSIONS_OPENAI_CODEX_PROVIDER_NAME,
33
- },
34
- },
35
- getModels: () => models,
36
- refreshModels: undefined,
37
- };
38
- }
39
-
40
- export function isOpenAICodexModel(model: { api?: string }): boolean {
41
- return model.api === "openai-codex-responses";
42
- }