pi-permission-system 0.1.5 → 0.1.7

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,7 +5,42 @@ 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
- ## [Unreleased]
8
+ ## [0.1.7] - 2026-03-10
9
+
10
+ ### Added
11
+ - `src/common.ts` — Shared utility module with `toRecord()`, `getNonEmptyString()`, `isPermissionState()`, `parseSimpleYamlMap()`, `extractFrontmatter()`
12
+ - `src/wildcard-matcher.ts` — Wildcard pattern compilation and matching with specificity sorting
13
+ - File stamp caching in `PermissionManager` for improved performance
14
+ - `tools.mcp` fallback permission for MCP operations
15
+ - MCP tool permission targets now inferred from configured server names in `mcp.json`
16
+
17
+ ### Changed
18
+ - Refactored `bash-filter.ts` to use shared `wildcard-matcher.ts` module
19
+ - Refactored `index.ts` to use shared `common.ts` utilities
20
+ - Refactored `permission-manager.ts` to use shared modules and caching
21
+ - Pre-compiled wildcard patterns are now reused across permission checks
22
+ - Updated README architecture documentation to reflect new module organization
23
+
24
+ ### Tests
25
+ - Added tests for MCP proxy tool inferring server-prefixed aliases from configured server names
26
+ - Added tests for `tools.mcp` fallback behavior
27
+ - Added tests for `task` using tool permissions instead of MCP fallback
28
+
29
+ ## [0.1.6] - 2026-03-09
30
+
31
+ ### Added
32
+ - Sanitized the `Available tools:` system prompt section so denied tools are removed before the agent starts.
33
+
34
+ ### Changed
35
+ - Updated README documentation to describe system-prompt tool sanitization and refreshed the displayed package version.
36
+
37
+ ### Fixed
38
+ - Prevented hidden tools from remaining advertised in the startup system prompt after runtime tool filtering.
39
+
40
+ ## [0.1.5] - 2026-03-09
41
+
42
+ ### Changed
43
+ - Added `repository`, `homepage`, and `bugs` package metadata so npm links back to the public GitHub repository and issue tracker.
9
44
 
10
45
  ## [0.1.4] - 2026-03-07
11
46
 
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 MasuRii
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MasuRii
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🔐 pi-permission-system
2
2
 
3
- [![Version](https://img.shields.io/badge/version-0.1.4-blue.svg)](package.json)
3
+ [![Version](https://img.shields.io/badge/version-0.1.7-blue.svg)](package.json)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
5
 
6
6
  Permission enforcement extension for the Pi coding agent that provides centralized, deterministic permission gates for tool, bash, MCP, skill, and special operations.
@@ -10,6 +10,7 @@ Permission enforcement extension for the Pi coding agent that provides centraliz
10
10
  ## Features
11
11
 
12
12
  - **Tool Filtering** — Hides disallowed tools from the agent before it starts (reduces "try another tool" behavior)
13
+ - **System Prompt Sanitization** — Removes denied tool entries from the `Available tools:` system prompt section so the agent only sees tools it can actually call
13
14
  - **Runtime Enforcement** — Blocks/asks/allows at tool call time with UI confirmation dialogs
14
15
  - **Bash Command Control** — Wildcard pattern matching for granular bash command permissions
15
16
  - **MCP Access Control** — Server and tool-level permissions for MCP operations
@@ -67,14 +68,15 @@ All permissions use one of three states:
67
68
 
68
69
  The extension integrates via Pi's lifecycle hooks:
69
70
 
70
- | Hook | Behavior |
71
- |----------------------|-----------------------------------------------------------------------|
72
- | `before_agent_start` | Filters active tools and removes denied skills from system prompt |
73
- | `tool_call` | Enforces permissions for every tool invocation |
74
- | `input` | Intercepts `/skill:<name>` requests and enforces skill policy |
71
+ | Hook | Behavior |
72
+ |----------------------|-------------------------------------------------------------------------------------------|
73
+ | `before_agent_start` | Filters active tools, removes denied tool entries from the system prompt, and hides denied skills |
74
+ | `tool_call` | Enforces permissions for every tool invocation |
75
+ | `input` | Intercepts `/skill:<name>` requests and enforces skill policy |
75
76
 
76
77
  **Additional behaviors:**
77
78
  - Unknown/unregistered tools are blocked before permission checks (prevents bypass attempts)
79
+ - The `Available tools:` system prompt section is rewritten to match the filtered active tool set
78
80
  - The `task` delegation tool is restricted to the `orchestrator` agent only
79
81
  - When a subagent hits an `ask` permission without direct UI access, the request can be forwarded to the main interactive session for confirmation
80
82
  - When a subagent triggers an `ask` permission without UI access, the request can be forwarded to the main session and answered there
@@ -109,9 +111,13 @@ permission:
109
111
  tools:
110
112
  read: allow
111
113
  write: deny
114
+ mcp: allow
112
115
  bash:
113
116
  git status: allow
114
117
  git *: ask
118
+ mcp:
119
+ chrome_devtools_*: deny
120
+ exa_*: allow
115
121
  skills:
116
122
  "*": ask
117
123
  ---
@@ -119,6 +125,8 @@ permission:
119
125
 
120
126
  **Precedence:** Agent frontmatter overrides global config (shallow-merged per section).
121
127
 
128
+ **MCP behavior:** `permission.tools.mcp` is the coarse entry/fallback permission for the built-in `mcp` tool. More specific `permission.mcp` target rules override that fallback when they match.
129
+
122
130
  **Limitations:** The frontmatter parser is intentionally minimal. Use only `key: value` scalars and nested maps. Avoid arrays, multi-line scalars, and YAML anchors.
123
131
 
124
132
  ---
@@ -154,18 +162,22 @@ Controls built-in tools by exact name (no wildcards):
154
162
  | `grep` | Pattern searching |
155
163
  | `find` | File discovery |
156
164
  | `ls` | Directory listing |
165
+ | `mcp` | MCP proxy tool entry/fallback |
157
166
 
158
167
  ```jsonc
159
168
  {
160
169
  "tools": {
161
170
  "read": "allow",
162
171
  "write": "deny",
163
- "edit": "deny"
172
+ "edit": "deny",
173
+ "mcp": "allow"
164
174
  }
165
175
  }
166
176
  ```
167
177
 
168
178
  > **Note:** Setting `tools.bash` affects the *default* for bash commands, but `bash` patterns can provide command-level overrides.
179
+ >
180
+ > **Note:** Setting `tools.mcp` controls coarse access to the built-in `mcp` tool. Specific `mcp` rules still override it when a target pattern matches.
169
181
 
170
182
  ### `bash`
171
183
 
@@ -188,7 +200,7 @@ Command patterns use `*` wildcards and match against the full command string. Pa
188
200
 
189
201
  ### `mcp`
190
202
 
191
- MCP permissions match against derived targets from tool input:
203
+ MCP permissions match against derived targets from tool input. These rules are more specific than `tools.mcp` and override that fallback when a pattern matches:
192
204
 
193
205
  | Target Type | Examples |
194
206
  |-------------------|---------------------------------------------|
@@ -210,6 +222,35 @@ MCP permissions match against derived targets from tool input:
210
222
 
211
223
  > **Note:** Baseline discovery targets may auto-allow when you permit any MCP rule.
212
224
 
225
+ #### MCP Tool Fallback via `tools.mcp`
226
+
227
+ The `mcp` built-in tool can use `tools.mcp` as an entry permission point. This provides a fallback when no specific MCP pattern matches:
228
+
229
+ ```jsonc
230
+ {
231
+ "tools": {
232
+ "mcp": "allow"
233
+ }
234
+ }
235
+ ```
236
+
237
+ This is useful for per-agent configurations where you want to grant MCP access broadly:
238
+
239
+ ```yaml
240
+ # In ~/.pi/agent/agents/researcher.md
241
+ ---
242
+ name: researcher
243
+ permission:
244
+ tools:
245
+ mcp: allow
246
+ ---
247
+ ```
248
+
249
+ The permission resolution order for MCP operations:
250
+ 1. Specific `mcp` patterns (e.g., `myServer:toolName`, `myServer_*`)
251
+ 2. `tools.mcp` fallback (if set)
252
+ 3. `defaultPolicy.mcp`
253
+
213
254
  ### `skills`
214
255
 
215
256
  Skill name patterns use `*` wildcards:
@@ -322,8 +363,10 @@ This keeps `ask` policies usable even when the original permission check happens
322
363
  index.ts → Root Pi entrypoint shim
323
364
  src/
324
365
  ├── index.ts → Extension bootstrap, permission checks, and subagent forwarding
325
- ├── permission-manager.ts → Policy loading, merging, and resolution
326
- ├── bash-filter.ts → Wildcard pattern matching with specificity sorting
366
+ ├── permission-manager.ts → Policy loading, merging, and resolution with caching
367
+ ├── bash-filter.ts → Bash command wildcard pattern matching
368
+ ├── wildcard-matcher.ts → Shared wildcard pattern compilation and matching
369
+ ├── common.ts → Shared utilities (YAML parsing, type guards, etc.)
327
370
  ├── tool-registry.ts → Registered tool name resolution
328
371
  ├── types.ts → TypeScript type definitions
329
372
  └── test.ts → Test runner
@@ -333,6 +376,23 @@ config/
333
376
  └── config.example.json → Starter configuration template
334
377
  ```
335
378
 
379
+ #### Module Organization
380
+
381
+ The extension uses a modular architecture with shared utilities:
382
+
383
+ | Module | Purpose |
384
+ |--------|---------|
385
+ | `common.ts` | Shared utilities: `toRecord()`, `getNonEmptyString()`, `isPermissionState()`, `parseSimpleYamlMap()`, `extractFrontmatter()` |
386
+ | `wildcard-matcher.ts` | Compile-once wildcard patterns with specificity sorting: `compileWildcardPatterns()`, `findCompiledWildcardMatch()` |
387
+ | `permission-manager.ts` | Policy resolution with file stamp caching for performance |
388
+ | `bash-filter.ts` | Uses shared wildcard matcher for bash command patterns |
389
+
390
+ #### Performance Optimizations
391
+
392
+ - **File stamp caching**: Configurations are cached with file modification timestamps to avoid redundant reads
393
+ - **Pre-compiled patterns**: Wildcard patterns are compiled to regex once and reused across permission checks
394
+ - **Resolved permissions caching**: Merged agent+global permissions are cached per-agent with invalidation on file changes
395
+
336
396
  ### Threat Model
337
397
 
338
398
  **Goal:** Enforce policy at the host level, not the model level.
@@ -1,27 +1,27 @@
1
- {
2
- "defaultPolicy": {
3
- "tools": "ask",
4
- "bash": "ask",
5
- "mcp": "ask",
6
- "skills": "ask",
7
- "special": "ask"
8
- },
9
- "tools": {
10
- "read": "allow",
11
- "write": "deny"
12
- },
13
- "bash": {
14
- "git status": "allow",
15
- "git *": "ask"
16
- },
17
- "mcp": {
18
- "mcp_status": "allow"
19
- },
20
- "skills": {
21
- "*": "ask"
22
- },
23
- "special": {
24
- "doom_loop": "deny",
25
- "external_directory": "ask"
26
- }
27
- }
1
+ {
2
+ "defaultPolicy": {
3
+ "tools": "ask",
4
+ "bash": "ask",
5
+ "mcp": "ask",
6
+ "skills": "ask",
7
+ "special": "ask"
8
+ },
9
+ "tools": {
10
+ "read": "allow",
11
+ "write": "deny"
12
+ },
13
+ "bash": {
14
+ "git status": "allow",
15
+ "git *": "ask"
16
+ },
17
+ "mcp": {
18
+ "mcp_status": "allow"
19
+ },
20
+ "skills": {
21
+ "*": "ask"
22
+ },
23
+ "special": {
24
+ "doom_loop": "deny",
25
+ "external_directory": "ask"
26
+ }
27
+ }
package/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- import permissionSystemExtension from "./src/index.js";
2
-
3
- export default permissionSystemExtension;
1
+ import permissionSystemExtension from "./src/index.js";
2
+
3
+ export default permissionSystemExtension;
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "pi-permission-system",
3
- "version": "0.1.5",
4
- "description": "Permission enforcement extension for the Pi coding agent.",
5
- "type": "module",
6
- "main": "./index.ts",
7
- "exports": {
8
- ".": "./index.ts"
9
- },
10
- "files": [
11
- "index.ts",
12
- "src",
13
- "config/config.example.json",
14
- "schemas/permissions.schema.json",
15
- "asset",
16
- "README.md",
17
- "CHANGELOG.md",
18
- "LICENSE"
19
- ],
20
- "scripts": {
21
- "build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
22
- "lint": "npm run build",
23
- "test": "bun ./src/test.ts",
24
- "check": "npm run lint && npm run test"
25
- },
26
- "keywords": [
27
- "pi-package",
28
- "pi",
29
- "pi-extension",
30
- "permissions",
31
- "policy",
32
- "coding-agent"
33
- ],
34
- "author": "MasuRii",
35
- "license": "MIT",
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/MasuRii/pi-permission-system.git"
39
- },
40
- "homepage": "https://github.com/MasuRii/pi-permission-system#readme",
41
- "bugs": {
42
- "url": "https://github.com/MasuRii/pi-permission-system/issues"
43
- },
44
- "engines": {
45
- "node": ">=20"
46
- },
47
- "publishConfig": {
48
- "access": "public"
49
- },
50
- "pi": {
51
- "extensions": [
52
- "./index.ts"
53
- ]
54
- },
55
- "peerDependencies": {
56
- "@mariozechner/pi-coding-agent": "*",
57
- "@sinclair/typebox": "*"
58
- }
59
- }
1
+ {
2
+ "name": "pi-permission-system",
3
+ "version": "0.1.7",
4
+ "description": "Permission enforcement extension for the Pi coding agent.",
5
+ "type": "module",
6
+ "main": "./index.ts",
7
+ "exports": {
8
+ ".": "./index.ts"
9
+ },
10
+ "files": [
11
+ "index.ts",
12
+ "src",
13
+ "config/config.example.json",
14
+ "schemas/permissions.schema.json",
15
+ "asset",
16
+ "README.md",
17
+ "CHANGELOG.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
22
+ "lint": "npm run build",
23
+ "test": "bun ./src/test.ts",
24
+ "check": "npm run lint && npm run test"
25
+ },
26
+ "keywords": [
27
+ "pi-package",
28
+ "pi",
29
+ "pi-extension",
30
+ "permissions",
31
+ "policy",
32
+ "coding-agent"
33
+ ],
34
+ "author": "MasuRii",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/MasuRii/pi-permission-system.git"
39
+ },
40
+ "homepage": "https://github.com/MasuRii/pi-permission-system#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/MasuRii/pi-permission-system/issues"
43
+ },
44
+ "engines": {
45
+ "node": ">=20"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "pi": {
51
+ "extensions": [
52
+ "./index.ts"
53
+ ]
54
+ },
55
+ "peerDependencies": {
56
+ "@mariozechner/pi-coding-agent": "*",
57
+ "@sinclair/typebox": "*"
58
+ }
59
+ }
@@ -1,86 +1,86 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://pi-coding-agent.local/schemas/permissions.schema.json",
4
- "title": "PI Permission Configuration",
5
- "type": "object",
6
- "additionalProperties": false,
7
- "properties": {
8
- "$schema": {
9
- "type": "string"
10
- },
11
- "defaultPolicy": {
12
- "type": "object",
13
- "additionalProperties": false,
14
- "required": ["tools", "bash", "mcp", "skills"],
15
- "properties": {
16
- "tools": {
17
- "$ref": "#/$defs/permissionState"
18
- },
19
- "bash": {
20
- "$ref": "#/$defs/permissionState"
21
- },
22
- "mcp": {
23
- "$ref": "#/$defs/permissionState"
24
- },
25
- "skills": {
26
- "$ref": "#/$defs/permissionState"
27
- },
28
- "special": {
29
- "$ref": "#/$defs/permissionState"
30
- }
31
- }
32
- },
33
- "tools": {
34
- "$ref": "#/$defs/permissionMap"
35
- },
36
- "bash": {
37
- "$ref": "#/$defs/permissionMap"
38
- },
39
- "mcp": {
40
- "$ref": "#/$defs/permissionMap"
41
- },
42
- "skills": {
43
- "$ref": "#/$defs/permissionMap"
44
- },
45
- "special": {
46
- "type": "object",
47
- "additionalProperties": false,
48
- "properties": {
49
- "doom_loop": {
50
- "$ref": "#/$defs/permissionState"
51
- },
52
- "external_directory": {
53
- "$ref": "#/$defs/permissionState"
54
- },
55
- "tool_call_limit": {
56
- "oneOf": [
57
- {
58
- "$ref": "#/$defs/permissionState"
59
- },
60
- {
61
- "type": "integer",
62
- "minimum": 0
63
- }
64
- ]
65
- }
66
- }
67
- }
68
- },
69
- "required": ["defaultPolicy"],
70
- "$defs": {
71
- "permissionState": {
72
- "type": "string",
73
- "enum": ["allow", "deny", "ask"]
74
- },
75
- "permissionMap": {
76
- "type": "object",
77
- "propertyNames": {
78
- "type": "string",
79
- "minLength": 1
80
- },
81
- "additionalProperties": {
82
- "$ref": "#/$defs/permissionState"
83
- }
84
- }
85
- }
86
- }
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://pi-coding-agent.local/schemas/permissions.schema.json",
4
+ "title": "PI Permission Configuration",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "$schema": {
9
+ "type": "string"
10
+ },
11
+ "defaultPolicy": {
12
+ "type": "object",
13
+ "additionalProperties": false,
14
+ "required": ["tools", "bash", "mcp", "skills"],
15
+ "properties": {
16
+ "tools": {
17
+ "$ref": "#/$defs/permissionState"
18
+ },
19
+ "bash": {
20
+ "$ref": "#/$defs/permissionState"
21
+ },
22
+ "mcp": {
23
+ "$ref": "#/$defs/permissionState"
24
+ },
25
+ "skills": {
26
+ "$ref": "#/$defs/permissionState"
27
+ },
28
+ "special": {
29
+ "$ref": "#/$defs/permissionState"
30
+ }
31
+ }
32
+ },
33
+ "tools": {
34
+ "$ref": "#/$defs/permissionMap"
35
+ },
36
+ "bash": {
37
+ "$ref": "#/$defs/permissionMap"
38
+ },
39
+ "mcp": {
40
+ "$ref": "#/$defs/permissionMap"
41
+ },
42
+ "skills": {
43
+ "$ref": "#/$defs/permissionMap"
44
+ },
45
+ "special": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "properties": {
49
+ "doom_loop": {
50
+ "$ref": "#/$defs/permissionState"
51
+ },
52
+ "external_directory": {
53
+ "$ref": "#/$defs/permissionState"
54
+ },
55
+ "tool_call_limit": {
56
+ "oneOf": [
57
+ {
58
+ "$ref": "#/$defs/permissionState"
59
+ },
60
+ {
61
+ "type": "integer",
62
+ "minimum": 0
63
+ }
64
+ ]
65
+ }
66
+ }
67
+ }
68
+ },
69
+ "required": ["defaultPolicy"],
70
+ "$defs": {
71
+ "permissionState": {
72
+ "type": "string",
73
+ "enum": ["allow", "deny", "ask"]
74
+ },
75
+ "permissionMap": {
76
+ "type": "object",
77
+ "propertyNames": {
78
+ "type": "string",
79
+ "minLength": 1
80
+ },
81
+ "additionalProperties": {
82
+ "$ref": "#/$defs/permissionState"
83
+ }
84
+ }
85
+ }
86
+ }