pi-permission-system 0.4.6 → 0.4.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 +12 -1
- package/README.md +14 -9
- package/package.json +11 -9
- package/schemas/permissions.schema.json +0 -11
- package/src/common.ts +35 -0
- package/src/config-modal.ts +223 -231
- package/src/extension-config.ts +25 -9
- package/src/index.ts +67 -68
- package/src/logging.ts +7 -8
- package/src/model-option-compatibility.ts +8 -5
- package/src/permission-forwarding.ts +29 -0
- package/src/permission-manager.ts +195 -68
- package/src/skill-prompt-sanitizer.ts +2 -34
- package/src/types-shims.d.ts +6 -0
- package/src/zellij-modal.ts +1 -1
- package/tests/config-modal.test.ts +32 -29
- package/tests/permission-system.test.ts +158 -17
- package/config.json +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,18 @@ 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
|
-
## [
|
|
8
|
+
## [0.4.7] - 2026-05-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Documented `PI_PERMISSION_SYSTEM_CONFIG_PATH` and `PI_PERMISSION_SYSTEM_LOGS_DIR` overrides for custom config and log locations.
|
|
12
|
+
- Added artifact validation to release checks for config defaults, schema support, README references, and package script safety.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Enforced trusted global/system `deny` floors so project-local policy layers can tighten permissions without relaxing higher-trust denies.
|
|
16
|
+
- Switched permission review audit entries to metadata hashes and lengths for prompts, commands, denial reasons, and tool input previews instead of raw sensitive content.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Stopped publishing `config.json` in the package so fresh installs use the runtime default with yolo mode off by default (thanks to @Nateowami for PR #18).
|
|
9
20
|
|
|
10
21
|
## [0.4.6] - 2026-04-28
|
|
11
22
|
|
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ The extension integrates via Pi's lifecycle hooks:
|
|
|
93
93
|
- Extension-provided tools like `task`, `mcp`, and third-party tools are handled by exact registered name instead of private built-in hardcodes
|
|
94
94
|
- When a subagent hits an `ask` permission without direct UI access, the request can be forwarded to the main interactive session for confirmation
|
|
95
95
|
- Generic extension-tool approval prompts include a bounded input preview; built-in file tools use concise human-readable summaries instead of raw multiline JSON
|
|
96
|
-
- Permission review logs include
|
|
96
|
+
- Permission review logs include redacted prompt/input metadata for auditing without writing raw prompts, commands, or tool payload previews
|
|
97
97
|
- Path-bearing file tools (`read`, `write`, `edit`, `find`, `grep`, `ls`) evaluate `special.external_directory` before their normal tool permission when an explicit path points outside `ctx.cwd`
|
|
98
98
|
|
|
99
99
|
## Configuration
|
|
@@ -102,6 +102,8 @@ The extension integrates via Pi's lifecycle hooks:
|
|
|
102
102
|
|
|
103
103
|
**Location:** global Pi extension config (default: `~/.pi/agent/extensions/pi-permission-system/config.json`, respects `PI_CODING_AGENT_DIR`)
|
|
104
104
|
|
|
105
|
+
Set `PI_PERMISSION_SYSTEM_CONFIG_PATH` to point this extension at a specific config file when the default global path is not appropriate.
|
|
106
|
+
|
|
105
107
|
The extension creates this file automatically when it is missing. It controls only extension-local logging behavior:
|
|
106
108
|
|
|
107
109
|
```json
|
|
@@ -118,7 +120,7 @@ The extension creates this file automatically when it is missing. It controls on
|
|
|
118
120
|
| `permissionReviewLog` | `true` | Enables the permission request/denial review log at `logs/pi-permission-system-permission-review.jsonl` |
|
|
119
121
|
| `yoloMode` | `false` | Auto-approves `ask` results instead of prompting when yolo mode is enabled |
|
|
120
122
|
|
|
121
|
-
Both logs write to files only under the extension directory. No debug output is printed to the terminal.
|
|
123
|
+
Both logs write to files only under the extension directory by default. Set `PI_PERMISSION_SYSTEM_LOGS_DIR` to redirect review/debug logs to a specific directory. No debug output is printed to the terminal.
|
|
122
124
|
|
|
123
125
|
### Global Policy File
|
|
124
126
|
|
|
@@ -181,7 +183,7 @@ Project-local files use the same formats as the global policy file and global ag
|
|
|
181
183
|
3. Global agent frontmatter
|
|
182
184
|
4. Project agent frontmatter
|
|
183
185
|
|
|
184
|
-
Later layers override earlier layers within the same permission category. For wildcard-based sections like `bash`, `mcp`, `skills`, and `special`, matching still follows
|
|
186
|
+
Later trusted layers override earlier layers within the same permission category, and project-local layers can tighten policy by adding `deny` rules. Project-local policy cannot relax a `deny` from the global policy file or global agent frontmatter: an `allow` or `ask` in a project policy is ignored when the latest matching trusted layer is `deny`. For wildcard-based sections like `bash`, `mcp`, `skills`, and `special`, matching still follows **last matching rule wins** within the applicable trust boundary, with global/system `deny` rules acting as floors for project-local overrides.
|
|
185
187
|
|
|
186
188
|
---
|
|
187
189
|
|
|
@@ -322,7 +324,6 @@ Reserved permission checks:
|
|
|
322
324
|
|----------------------|------------------------------------------|
|
|
323
325
|
| `doom_loop` | Controls doom loop detection behavior |
|
|
324
326
|
| `external_directory` | Enforces ask/allow/deny decisions for path-bearing built-in tools (`read`, `write`, `edit`, `find`, `grep`, `ls`) when they target paths outside the active working directory |
|
|
325
|
-
| `tool_call_limit` | *(schema only, not enforced yet)* |
|
|
326
327
|
|
|
327
328
|
```jsonc
|
|
328
329
|
{
|
|
@@ -431,9 +432,10 @@ When the extension prompts, denies, or forwards permission requests, it can appe
|
|
|
431
432
|
```text
|
|
432
433
|
Default global logs directory: ~/.pi/agent/extensions/pi-permission-system/logs/
|
|
433
434
|
Actual global logs directory: $PI_CODING_AGENT_DIR/extensions/pi-permission-system/logs when PI_CODING_AGENT_DIR is set
|
|
435
|
+
Override logs directory: $PI_PERMISSION_SYSTEM_LOGS_DIR when set
|
|
434
436
|
```
|
|
435
437
|
|
|
436
|
-
- `pi-permission-system-permission-review.jsonl` — enabled by default for permission review/audit history, including
|
|
438
|
+
- `pi-permission-system-permission-review.jsonl` — enabled by default for permission review/audit history, including metadata hashes and lengths for prompts, commands, denial reasons, and tool input previews instead of raw sensitive content
|
|
437
439
|
- `pi-permission-system-debug.jsonl` — disabled by default and intended for troubleshooting
|
|
438
440
|
|
|
439
441
|
### Architecture
|
|
@@ -522,11 +524,14 @@ npx --yes ajv-cli@5 validate \
|
|
|
522
524
|
|
|
523
525
|
## Development
|
|
524
526
|
|
|
527
|
+
Runtime checks require Node.js 20+; the test suite requires Bun 1.1+.
|
|
528
|
+
|
|
525
529
|
```bash
|
|
526
|
-
npm run build
|
|
527
|
-
npm run lint
|
|
528
|
-
npm run
|
|
529
|
-
npm run
|
|
530
|
+
npm run build # Run TypeScript type checks
|
|
531
|
+
npm run lint # Run local static checks
|
|
532
|
+
npm run validate:artifacts # Validate JSON/schema/example artifacts
|
|
533
|
+
npm run test # Run Bun tests from ./tests
|
|
534
|
+
npm run check # Run static, artifact, and test checks
|
|
530
535
|
```
|
|
531
536
|
|
|
532
537
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-permission-system",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Permission enforcement extension for the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"index.ts",
|
|
12
12
|
"src",
|
|
13
13
|
"tests",
|
|
14
|
-
"config.json",
|
|
15
14
|
"config/config.example.json",
|
|
16
15
|
"schemas/permissions.schema.json",
|
|
17
16
|
"README.md",
|
|
@@ -19,10 +18,12 @@
|
|
|
19
18
|
"LICENSE"
|
|
20
19
|
],
|
|
21
20
|
"scripts": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"typecheck": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noEmit",
|
|
22
|
+
"build": "npm run typecheck",
|
|
23
|
+
"lint": "npm run typecheck",
|
|
24
|
+
"validate:artifacts": "node ./scripts/validate-artifacts.mjs",
|
|
24
25
|
"test": "bun ./tests/permission-system.test.ts && bun ./tests/config-modal.test.ts",
|
|
25
|
-
"check": "npm run lint && npm run test"
|
|
26
|
+
"check": "npm run lint && npm run validate:artifacts && npm run test"
|
|
26
27
|
},
|
|
27
28
|
"keywords": [
|
|
28
29
|
"pi-package",
|
|
@@ -47,7 +48,8 @@
|
|
|
47
48
|
"url": "https://github.com/MasuRii/pi-permission-system/issues"
|
|
48
49
|
},
|
|
49
50
|
"engines": {
|
|
50
|
-
"node": ">=20"
|
|
51
|
+
"node": ">=20",
|
|
52
|
+
"bun": ">=1.1.0"
|
|
51
53
|
},
|
|
52
54
|
"publishConfig": {
|
|
53
55
|
"access": "public"
|
|
@@ -58,9 +60,9 @@
|
|
|
58
60
|
]
|
|
59
61
|
},
|
|
60
62
|
"peerDependencies": {
|
|
61
|
-
"@mariozechner/pi-ai": "^0.
|
|
62
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
63
|
-
"@mariozechner/pi-tui": "^0.
|
|
63
|
+
"@mariozechner/pi-ai": "^0.72.0",
|
|
64
|
+
"@mariozechner/pi-coding-agent": "^0.72.0",
|
|
65
|
+
"@mariozechner/pi-tui": "^0.72.0",
|
|
64
66
|
"@sinclair/typebox": "^0.34.49"
|
|
65
67
|
}
|
|
66
68
|
}
|
package/src/common.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, normalize, resolve, sep } from "node:path";
|
|
3
|
+
|
|
1
4
|
import type { PermissionState } from "./types.js";
|
|
2
5
|
|
|
3
6
|
export function toRecord(value: unknown): Record<string, unknown> {
|
|
@@ -21,6 +24,38 @@ export function isPermissionState(value: unknown): value is PermissionState {
|
|
|
21
24
|
return value === "allow" || value === "deny" || value === "ask";
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
export function normalizePathForComparison(pathValue: string, cwd: string): string {
|
|
28
|
+
const trimmed = pathValue.trim().replace(/^["']|["']$/g, "");
|
|
29
|
+
if (!trimmed) {
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let normalizedPath = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
34
|
+
|
|
35
|
+
if (normalizedPath === "~") {
|
|
36
|
+
normalizedPath = homedir();
|
|
37
|
+
} else if (normalizedPath.startsWith("~/") || normalizedPath.startsWith("~\\")) {
|
|
38
|
+
normalizedPath = join(homedir(), normalizedPath.slice(2));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const absolutePath = resolve(cwd, normalizedPath);
|
|
42
|
+
const normalizedAbsolutePath = normalize(absolutePath);
|
|
43
|
+
return process.platform === "win32" ? normalizedAbsolutePath.toLowerCase() : normalizedAbsolutePath;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isPathWithinDirectory(pathValue: string, directory: string): boolean {
|
|
47
|
+
if (!pathValue || !directory) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (pathValue === directory) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const prefix = directory.endsWith(sep) ? directory : `${directory}${sep}`;
|
|
56
|
+
return pathValue.startsWith(prefix);
|
|
57
|
+
}
|
|
58
|
+
|
|
24
59
|
type StackNode = { indent: number; target: Record<string, unknown> };
|
|
25
60
|
|
|
26
61
|
export function parseSimpleYamlMap(input: string): Record<string, unknown> {
|