@gotgenes/pi-permission-system 10.10.0 → 11.0.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
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [11.0.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v10.10.1...pi-permission-system-v11.0.0) (2026-06-11)
9
+
10
+
11
+ ### ⚠ BREAKING CHANGES
12
+
13
+ * The permission system no longer auto-activates pi's off-by-default tools (`find`, `grep`, `ls`) in the main session. Users who want them active should enable them via pi's own `activeTools` configuration rather than relying on the permission system to expose every non-denied tool.
14
+
15
+ ### Features
16
+
17
+ * add getActive to ToolRegistry wired to pi.getActiveTools ([#385](https://github.com/gotgenes/pi-packages/issues/385)) ([79c4594](https://github.com/gotgenes/pi-packages/commit/79c459443294c1b58643b746e3511fc17c9f8961))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * respect pi's default active tool set in before_agent_start ([#385](https://github.com/gotgenes/pi-packages/issues/385)) ([bf5be48](https://github.com/gotgenes/pi-packages/commit/bf5be48ca8b06e8cb08f66d08eccb85af0673987))
23
+
24
+
25
+ ### Documentation
26
+
27
+ * clarify before_agent_start filters pi's active tool set ([#385](https://github.com/gotgenes/pi-packages/issues/385)) ([bdb5a6a](https://github.com/gotgenes/pi-packages/commit/bdb5a6a08e3c1bb611c8b1795c4d46856104b3b0))
28
+
29
+ ## [10.10.1](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v10.10.0...pi-permission-system-v10.10.1) (2026-06-11)
30
+
31
+
32
+ ### Documentation
33
+
34
+ * fix bash rule precedence examples and wording ([#387](https://github.com/gotgenes/pi-packages/issues/387)) ([9e18d6f](https://github.com/gotgenes/pi-packages/commit/9e18d6faab6e3ceaa1a8839f5b6753d5457a2a28))
35
+
8
36
  ## [10.10.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v10.9.0...pi-permission-system-v10.10.0) (2026-06-10)
9
37
 
10
38
 
@@ -23,9 +23,9 @@
23
23
  "edit": "deny",
24
24
  "bash": {
25
25
  "*": "ask",
26
+ "git *": "ask",
26
27
  "git status": "allow",
27
- "git diff": "allow",
28
- "git *": "ask"
28
+ "git diff": "allow"
29
29
  },
30
30
  "mcp": { "*": "ask", "mcp_status": "allow", "mcp_list": "allow" },
31
31
  "skill": { "*": "ask" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotgenes/pi-permission-system",
3
- "version": "10.10.0",
3
+ "version": "11.0.0",
4
4
  "description": "Permission enforcement extension for the Pi coding agent.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -86,9 +86,9 @@
86
86
  "edit": "deny",
87
87
  "bash": {
88
88
  "*": "ask",
89
+ "git *": "ask",
89
90
  "git status": "allow",
90
- "git diff": "allow",
91
- "git *": "ask"
91
+ "git diff": "allow"
92
92
  },
93
93
  "mcp": { "*": "ask", "mcp_status": "allow", "exa:*": "allow" },
94
94
  "skill": { "*": "ask", "librarian": "allow" },
@@ -38,7 +38,7 @@ export function shouldExposeTool(
38
38
  * Constructor deps:
39
39
  * - `session` — encapsulates all mutable session state and lifecycle operations
40
40
  * - `resolver` — owns permission-query surface: `getToolPermission`, `getPolicyCacheStamp`, skill check
41
- * - `toolRegistry` — Pi tool API subset (getAll + setActive)
41
+ * - `toolRegistry` — Pi tool API subset (getActive + setActive)
42
42
  */
43
43
  export class AgentPrepHandler {
44
44
  constructor(
@@ -56,10 +56,10 @@ export class AgentPrepHandler {
56
56
  this.session.refreshConfig(ctx);
57
57
 
58
58
  const agentName = this.session.resolveAgentName(ctx, event.systemPrompt);
59
- const allTools = this.toolRegistry.getAll();
59
+ const activeTools = this.toolRegistry.getActive();
60
60
  const allowedTools: string[] = [];
61
61
 
62
- for (const tool of allTools) {
62
+ for (const tool of activeTools) {
63
63
  const toolName = getToolNameFromValue(tool);
64
64
  if (!toolName) {
65
65
  continue;
package/src/index.ts CHANGED
@@ -152,6 +152,7 @@ export default function piPermissionSystemExtension(pi: ExtensionAPI): void {
152
152
 
153
153
  const toolRegistry = {
154
154
  getAll: () => pi.getAllTools(),
155
+ getActive: () => pi.getActiveTools(),
155
156
  setActive: (names: string[]) => pi.setActiveTools(names),
156
157
  };
157
158
 
@@ -2,7 +2,10 @@ import { getNonEmptyString, toRecord } from "./common";
2
2
 
3
3
  /** Narrow interface for the Pi tool API subset used by handler classes. */
4
4
  export interface ToolRegistry {
5
+ /** All registered tools (`pi.getAllTools()` — `ToolInfo[]`); kept defensively wide. */
5
6
  getAll(): unknown[];
7
+ /** Currently active tool names (`pi.getActiveTools()`). */
8
+ getActive(): string[];
6
9
  setActive(names: string[]): void;
7
10
  }
8
11
 
@@ -31,6 +31,7 @@ function makeEvent(systemPrompt = "You are an assistant.") {
31
31
  function makeToolRegistry(overrides: Partial<ToolRegistry> = {}): ToolRegistry {
32
32
  return {
33
33
  getAll: vi.fn().mockReturnValue([]),
34
+ getActive: vi.fn().mockReturnValue([]),
34
35
  setActive: vi.fn(),
35
36
  ...overrides,
36
37
  };
@@ -126,7 +127,7 @@ describe("AgentPrepHandler.handle", () => {
126
127
  const { handler, toolRegistry } = makeSetup({
127
128
  toolPermission: "deny",
128
129
  toolRegistry: {
129
- getAll: vi.fn().mockReturnValue([{ name: "write" }, { name: "read" }]),
130
+ getActive: vi.fn().mockReturnValue(["write", "read"]),
130
131
  },
131
132
  });
132
133
  await handler.handle(makeEvent(), makeCtx());
@@ -136,17 +137,44 @@ describe("AgentPrepHandler.handle", () => {
136
137
  it("includes allowed and ask tools in the active list", async () => {
137
138
  const { handler, toolRegistry } = makeSetup({
138
139
  toolRegistry: {
139
- getAll: vi.fn().mockReturnValue([{ name: "read" }, { name: "write" }]),
140
+ getActive: vi.fn().mockReturnValue(["read", "write"]),
140
141
  },
141
142
  });
142
143
  await handler.handle(makeEvent(), makeCtx());
143
144
  expect(toolRegistry.setActive).toHaveBeenCalledWith(["read", "write"]);
144
145
  });
145
146
 
147
+ it("does not activate registered tools pi left inactive (find/grep/ls)", async () => {
148
+ // Regression for #385: the active set is the base, not the full registry.
149
+ const { handler, toolRegistry } = makeSetup({
150
+ toolRegistry: {
151
+ getActive: vi.fn().mockReturnValue(["read", "bash", "edit", "write"]),
152
+ getAll: vi
153
+ .fn()
154
+ .mockReturnValue([
155
+ { name: "read" },
156
+ { name: "bash" },
157
+ { name: "edit" },
158
+ { name: "write" },
159
+ { name: "find" },
160
+ { name: "grep" },
161
+ { name: "ls" },
162
+ ]),
163
+ },
164
+ });
165
+ await handler.handle(makeEvent(), makeCtx());
166
+ expect(toolRegistry.setActive).toHaveBeenCalledWith([
167
+ "read",
168
+ "bash",
169
+ "edit",
170
+ "write",
171
+ ]);
172
+ });
173
+
146
174
  it("calls setActive once across repeated calls with the same allowed tools", async () => {
147
175
  const { handler, toolRegistry } = makeSetup({
148
176
  toolRegistry: {
149
- getAll: vi.fn().mockReturnValue([{ name: "read" }]),
177
+ getActive: vi.fn().mockReturnValue(["read"]),
150
178
  },
151
179
  });
152
180
  await handler.handle(makeEvent(), makeCtx());
@@ -123,6 +123,7 @@ export function makeToolRegistry(
123
123
  ): ToolRegistry {
124
124
  return {
125
125
  getAll: vi.fn().mockReturnValue([{ name: "read" }, { name: "bash" }]),
126
+ getActive: vi.fn().mockReturnValue(["read", "bash"]),
126
127
  setActive: vi.fn(),
127
128
  ...overrides,
128
129
  };
@@ -42,6 +42,8 @@ export interface FakePi {
42
42
  fire(event: string, input?: unknown, ctx?: unknown): Promise<unknown>;
43
43
  /** Minimal tool registry — returns the configured tool names. */
44
44
  getAllTools(): { name: string }[];
45
+ /** Active tool names (`pi.getActiveTools()` shape — bare strings). */
46
+ getActiveTools(): string[];
45
47
  setActiveTools(names: string[]): void;
46
48
  }
47
49
 
@@ -80,6 +82,9 @@ export function makeFakePi(options: MakeFakePiOptions = {}): FakePi {
80
82
  getAllTools(): { name: string }[] {
81
83
  return toolNames.map((name) => ({ name }));
82
84
  },
85
+ getActiveTools(): string[] {
86
+ return [...toolNames];
87
+ },
83
88
  setActiveTools: vi.fn(),
84
89
  // ── ExtensionAPI methods the factory touches (recorded) ────────────────
85
90
  on(event: string, handler: RecordedHandler): void {
@@ -363,6 +363,7 @@ describe("piPermissionSystemExtension ready event wiring", () => {
363
363
  ),
364
364
  registerCommand: vi.fn(),
365
365
  getAllTools: vi.fn().mockReturnValue([]),
366
+ getActiveTools: vi.fn().mockReturnValue([]),
366
367
  setActiveTools: vi.fn(),
367
368
  registerProvider: vi.fn(),
368
369
  events: { emit: emitSpy, on: vi.fn().mockReturnValue(() => undefined) },
@@ -56,6 +56,7 @@ describe("session_start handler consolidation", () => {
56
56
  },
57
57
  registerCommand: (): void => {},
58
58
  getAllTools: (): Array<{ name: string }> => [],
59
+ getActiveTools: (): string[] => [],
59
60
  setActiveTools: (): void => {},
60
61
  registerProvider: (): void => {},
61
62
  events: {
@@ -79,6 +80,7 @@ describe("session_start handler consolidation", () => {
79
80
  },
80
81
  registerCommand: (): void => {},
81
82
  getAllTools: (): Array<{ name: string }> => [],
83
+ getActiveTools: (): string[] => [],
82
84
  setActiveTools: (): void => {},
83
85
  registerProvider: (): void => {},
84
86
  events: {