pi-permission-system 0.3.1 → 0.4.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 +18 -0
- package/package.json +61 -61
- package/src/system-prompt-sanitizer.ts +116 -78
- package/src/test.ts +59 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ 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
|
+
## [0.4.0] - 2026-04-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- System prompt sanitizer now removes inactive tool guidelines from the `Guidelines:` section
|
|
12
|
+
- Guideline filtering based on allowed tools (e.g., removes task/mcp/bash/write guidance when tools are denied)
|
|
13
|
+
- New `TOOL_GUIDELINE_RULES` configuration for extensible guideline filtering
|
|
14
|
+
- Helper functions: `findSection()`, `removeLineSection()`, `sanitizeGuidelinesSection()`
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Updated `@mariozechner/pi-coding-agent` and `@mariozechner/pi-tui` peer dependencies to ^0.64.0
|
|
18
|
+
- Updated `@sinclair/typebox` peer dependency to ^0.34.49
|
|
19
|
+
- Refactored system prompt sanitizer to handle both `Available tools:` and `Guidelines:` sections
|
|
20
|
+
|
|
21
|
+
### Tests
|
|
22
|
+
- Added tests for system prompt sanitizer removing Available tools section
|
|
23
|
+
- Added tests for guideline filtering based on allowed tools
|
|
24
|
+
- Added tests for inactive built-in write/edit/task/mcp guidance removal
|
|
25
|
+
|
|
8
26
|
## [0.3.1] - 2026-03-24
|
|
9
27
|
|
|
10
28
|
### Added
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-permission-system",
|
|
3
|
-
"version": "0.
|
|
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.json",
|
|
14
|
-
"config/config.example.json",
|
|
15
|
-
"schemas/permissions.schema.json",
|
|
16
|
-
"asset",
|
|
17
|
-
"README.md",
|
|
18
|
-
"CHANGELOG.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
|
|
23
|
-
"lint": "npm run build",
|
|
24
|
-
"test": "bun ./src/test.ts && bun ./src/config-modal-test.ts",
|
|
25
|
-
"check": "npm run lint && npm run test"
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"pi-package",
|
|
29
|
-
"pi",
|
|
30
|
-
"pi-extension",
|
|
31
|
-
"permissions",
|
|
32
|
-
"policy",
|
|
33
|
-
"coding-agent"
|
|
34
|
-
],
|
|
35
|
-
"author": "MasuRii",
|
|
36
|
-
"license": "MIT",
|
|
37
|
-
"repository": {
|
|
38
|
-
"type": "git",
|
|
39
|
-
"url": "git+https://github.com/MasuRii/pi-permission-system.git"
|
|
40
|
-
},
|
|
41
|
-
"homepage": "https://github.com/MasuRii/pi-permission-system#readme",
|
|
42
|
-
"bugs": {
|
|
43
|
-
"url": "https://github.com/MasuRii/pi-permission-system/issues"
|
|
44
|
-
},
|
|
45
|
-
"engines": {
|
|
46
|
-
"node": ">=20"
|
|
47
|
-
},
|
|
48
|
-
"publishConfig": {
|
|
49
|
-
"access": "public"
|
|
50
|
-
},
|
|
51
|
-
"pi": {
|
|
52
|
-
"extensions": [
|
|
53
|
-
"./index.ts"
|
|
54
|
-
]
|
|
55
|
-
},
|
|
56
|
-
"peerDependencies": {
|
|
57
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
58
|
-
"@mariozechner/pi-tui": "^0.
|
|
59
|
-
"@sinclair/typebox": "^0.34.
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-permission-system",
|
|
3
|
+
"version": "0.4.0",
|
|
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.json",
|
|
14
|
+
"config/config.example.json",
|
|
15
|
+
"schemas/permissions.schema.json",
|
|
16
|
+
"asset",
|
|
17
|
+
"README.md",
|
|
18
|
+
"CHANGELOG.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
|
|
23
|
+
"lint": "npm run build",
|
|
24
|
+
"test": "bun ./src/test.ts && bun ./src/config-modal-test.ts",
|
|
25
|
+
"check": "npm run lint && npm run test"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"pi-package",
|
|
29
|
+
"pi",
|
|
30
|
+
"pi-extension",
|
|
31
|
+
"permissions",
|
|
32
|
+
"policy",
|
|
33
|
+
"coding-agent"
|
|
34
|
+
],
|
|
35
|
+
"author": "MasuRii",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/MasuRii/pi-permission-system.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/MasuRii/pi-permission-system#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/MasuRii/pi-permission-system/issues"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"pi": {
|
|
52
|
+
"extensions": [
|
|
53
|
+
"./index.ts"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@mariozechner/pi-coding-agent": "^0.64.0",
|
|
58
|
+
"@mariozechner/pi-tui": "^0.64.0",
|
|
59
|
+
"@sinclair/typebox": "^0.34.49"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -3,18 +3,59 @@ export interface SanitizeSystemPromptResult {
|
|
|
3
3
|
removed: boolean;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
type
|
|
7
|
-
name: string;
|
|
8
|
-
lines: string[];
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
type ToolPromptSection = {
|
|
6
|
+
type LineSection = {
|
|
12
7
|
start: number;
|
|
13
8
|
end: number;
|
|
14
|
-
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type GuidelineRule = {
|
|
12
|
+
matches: (guideline: string) => boolean;
|
|
13
|
+
shouldKeep: (allowedTools: ReadonlySet<string>) => boolean;
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
const AVAILABLE_TOOLS_SECTION_HEADER = "Available tools:";
|
|
17
|
+
const GUIDELINES_SECTION_HEADER = "Guidelines:";
|
|
18
|
+
|
|
19
|
+
const TOOL_GUIDELINE_RULES: readonly GuidelineRule[] = [
|
|
20
|
+
{
|
|
21
|
+
matches: (guideline) => guideline === "use bash for file operations like ls, rg, find",
|
|
22
|
+
shouldKeep: (allowedTools) => allowedTools.has("bash"),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
matches: (guideline) => guideline === "prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)",
|
|
26
|
+
shouldKeep: (allowedTools) =>
|
|
27
|
+
allowedTools.has("bash") && (allowedTools.has("grep") || allowedTools.has("find") || allowedTools.has("ls")),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
matches: (guideline) =>
|
|
31
|
+
guideline === "use read to examine files before editing. you must use this tool instead of cat or sed."
|
|
32
|
+
|| guideline === "use read to examine files instead of cat or sed.",
|
|
33
|
+
shouldKeep: (allowedTools) => allowedTools.has("read"),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
matches: (guideline) => guideline === "use edit for precise changes (old text must match exactly)",
|
|
37
|
+
shouldKeep: (allowedTools) => allowedTools.has("edit"),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
matches: (guideline) => guideline === "use write only for new files or complete rewrites",
|
|
41
|
+
shouldKeep: (allowedTools) => allowedTools.has("write"),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
matches: (guideline) =>
|
|
45
|
+
guideline === "when summarizing your actions, output plain text directly - do not use cat or bash to display what you did",
|
|
46
|
+
shouldKeep: (allowedTools) => allowedTools.has("edit") || allowedTools.has("write"),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
matches: (guideline) =>
|
|
50
|
+
guideline === "use task when work should be delegated to one or more specialized agents instead of handled entirely in the current session.",
|
|
51
|
+
shouldKeep: (allowedTools) => allowedTools.has("task"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
matches: (guideline) =>
|
|
55
|
+
guideline === "use mcp for mcp discovery first: search by capability, describe one exact tool name, then call it.",
|
|
56
|
+
shouldKeep: (allowedTools) => allowedTools.has("mcp"),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
18
59
|
|
|
19
60
|
function normalizePrompt(prompt: string): string {
|
|
20
61
|
return (prompt || "").replace(/\r\n/g, "\n");
|
|
@@ -24,77 +65,89 @@ function collapseExtraBlankLines(text: string): string {
|
|
|
24
65
|
return text.replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
25
66
|
}
|
|
26
67
|
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
68
|
+
function normalizeGuidelineText(line: string): string {
|
|
69
|
+
return line.trim().replace(/^[-*]\s+/, "").replace(/\s+/g, " ").toLowerCase();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isTopLevelSectionHeader(line: string): boolean {
|
|
73
|
+
const trimmed = line.trim();
|
|
74
|
+
return trimmed.length > 0 && trimmed.endsWith(":") && !trimmed.startsWith("-");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function findSection(lines: readonly string[], header: string): LineSection | null {
|
|
78
|
+
const start = lines.findIndex((line) => line.trim() === header);
|
|
30
79
|
if (start === -1) {
|
|
31
80
|
return null;
|
|
32
81
|
}
|
|
33
82
|
|
|
34
|
-
|
|
35
|
-
let index = start + 1;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const line = lines[index];
|
|
39
|
-
const trimmed = line.trim();
|
|
40
|
-
|
|
41
|
-
if (!trimmed) {
|
|
42
|
-
index += 1;
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!trimmed.startsWith("- ")) {
|
|
83
|
+
let end = lines.length;
|
|
84
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
85
|
+
if (isTopLevelSectionHeader(lines[index])) {
|
|
86
|
+
end = index;
|
|
47
87
|
break;
|
|
48
88
|
}
|
|
89
|
+
}
|
|
49
90
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
91
|
+
return { start, end };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function removeLineSection(lines: readonly string[], section: LineSection | null): { lines: string[]; removed: boolean } {
|
|
95
|
+
if (!section) {
|
|
96
|
+
return { lines: [...lines], removed: false };
|
|
97
|
+
}
|
|
54
98
|
|
|
55
|
-
|
|
56
|
-
|
|
99
|
+
return {
|
|
100
|
+
lines: [...lines.slice(0, section.start), ...lines.slice(section.end)],
|
|
101
|
+
removed: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
57
104
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const nextTrimmed = nextLine.trim();
|
|
105
|
+
function shouldKeepGuideline(line: string, allowedTools: ReadonlySet<string>): boolean {
|
|
106
|
+
const normalized = normalizeGuidelineText(line);
|
|
61
107
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
108
|
+
for (const rule of TOOL_GUIDELINE_RULES) {
|
|
109
|
+
if (rule.matches(normalized)) {
|
|
110
|
+
return rule.shouldKeep(allowedTools);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
67
113
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
71
116
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
117
|
+
function sanitizeGuidelinesSection(lines: readonly string[], allowedTools: ReadonlySet<string>): { lines: string[]; removed: boolean } {
|
|
118
|
+
const section = findSection(lines, GUIDELINES_SECTION_HEADER);
|
|
119
|
+
if (!section) {
|
|
120
|
+
return { lines: [...lines], removed: false };
|
|
121
|
+
}
|
|
75
122
|
|
|
76
|
-
|
|
77
|
-
|
|
123
|
+
const before = lines.slice(0, section.start + 1);
|
|
124
|
+
const after = lines.slice(section.end);
|
|
125
|
+
const body = lines.slice(section.start + 1, section.end);
|
|
126
|
+
const filteredBody = body.filter((line) => {
|
|
127
|
+
const trimmed = line.trim();
|
|
128
|
+
if (!trimmed.startsWith("- ")) {
|
|
129
|
+
return true;
|
|
78
130
|
}
|
|
79
131
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
132
|
+
return shouldKeepGuideline(line, allowedTools);
|
|
133
|
+
});
|
|
83
134
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
});
|
|
135
|
+
const removed = filteredBody.length !== body.length;
|
|
136
|
+
if (!removed) {
|
|
137
|
+
return { lines: [...lines], removed: false };
|
|
88
138
|
}
|
|
89
139
|
|
|
90
|
-
|
|
91
|
-
|
|
140
|
+
const hasBullet = filteredBody.some((line) => line.trim().startsWith("- "));
|
|
141
|
+
if (!hasBullet) {
|
|
142
|
+
return {
|
|
143
|
+
lines: [...lines.slice(0, section.start), ...after],
|
|
144
|
+
removed: true,
|
|
145
|
+
};
|
|
92
146
|
}
|
|
93
147
|
|
|
94
148
|
return {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
entries,
|
|
149
|
+
lines: [...before, ...filteredBody, ...after],
|
|
150
|
+
removed: true,
|
|
98
151
|
};
|
|
99
152
|
}
|
|
100
153
|
|
|
@@ -102,29 +155,14 @@ export function sanitizeAvailableToolsSection(
|
|
|
102
155
|
systemPrompt: string,
|
|
103
156
|
allowedToolNames: readonly string[],
|
|
104
157
|
): SanitizeSystemPromptResult {
|
|
105
|
-
const section = parseAvailableToolsSection(systemPrompt);
|
|
106
|
-
if (!section) {
|
|
107
|
-
return { prompt: systemPrompt, removed: false };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
158
|
const allowedTools = new Set(allowedToolNames.map((toolName) => toolName.trim()).filter(Boolean));
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const lines = normalizePrompt(systemPrompt).split("\n");
|
|
118
|
-
const replacement = visibleEntries.length > 0
|
|
119
|
-
? [lines[section.start], ...visibleEntries.flatMap((entry) => entry.lines)]
|
|
120
|
-
: [];
|
|
159
|
+
const normalizedLines = normalizePrompt(systemPrompt).split("\n");
|
|
160
|
+
const removedToolsSection = removeLineSection(normalizedLines, findSection(normalizedLines, AVAILABLE_TOOLS_SECTION_HEADER));
|
|
161
|
+
const sanitizedGuidelines = sanitizeGuidelinesSection(removedToolsSection.lines, allowedTools);
|
|
162
|
+
const removed = removedToolsSection.removed || sanitizedGuidelines.removed;
|
|
121
163
|
|
|
122
164
|
return {
|
|
123
|
-
prompt: collapseExtraBlankLines(
|
|
124
|
-
|
|
125
|
-
...replacement,
|
|
126
|
-
...lines.slice(section.end),
|
|
127
|
-
].join("\n")),
|
|
128
|
-
removed: true,
|
|
165
|
+
prompt: removed ? collapseExtraBlankLines(sanitizedGuidelines.lines.join("\n")) : systemPrompt,
|
|
166
|
+
removed,
|
|
129
167
|
};
|
|
130
168
|
}
|
package/src/test.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { PermissionManager } from "./permission-manager.js";
|
|
15
15
|
import { checkRequestedToolRegistration, getToolNameFromValue } from "./tool-registry.js";
|
|
16
16
|
import { getPermissionSystemStatus } from "./status.js";
|
|
17
|
+
import { sanitizeAvailableToolsSection } from "./system-prompt-sanitizer.js";
|
|
17
18
|
import type { GlobalPermissionConfig } from "./types.js";
|
|
18
19
|
import { canResolveAskPermissionRequest, shouldAutoApprovePermissionState } from "./yolo-mode.js";
|
|
19
20
|
|
|
@@ -207,6 +208,64 @@ runTest("Permission-system status is only exposed when yolo mode is enabled", ()
|
|
|
207
208
|
);
|
|
208
209
|
});
|
|
209
210
|
|
|
211
|
+
runTest("System prompt sanitizer removes the Available tools section and surrounding boilerplate", () => {
|
|
212
|
+
const prompt = [
|
|
213
|
+
"Available tools:",
|
|
214
|
+
"- read: Read file contents",
|
|
215
|
+
"- mcp: Discover, inspect, and call MCP tools across configured servers",
|
|
216
|
+
"",
|
|
217
|
+
"In addition to the tools above, you may have access to other custom tools depending on the project.",
|
|
218
|
+
"",
|
|
219
|
+
"Guidelines:",
|
|
220
|
+
"- Use mcp for MCP discovery first: search by capability, describe one exact tool name, then call it.",
|
|
221
|
+
"- Be concise in your responses",
|
|
222
|
+
].join("\n");
|
|
223
|
+
|
|
224
|
+
const result = sanitizeAvailableToolsSection(prompt, ["read", "mcp"]);
|
|
225
|
+
|
|
226
|
+
assert.equal(result.removed, true);
|
|
227
|
+
assert.equal(result.prompt.includes("Available tools:"), false);
|
|
228
|
+
assert.equal(result.prompt.includes("In addition to the tools above"), false);
|
|
229
|
+
assert.match(result.prompt, /Guidelines:/);
|
|
230
|
+
assert.match(result.prompt, /Use mcp for MCP discovery first/i);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
runTest("System prompt sanitizer removes denied tool guidelines while keeping global guidance", () => {
|
|
234
|
+
const prompt = [
|
|
235
|
+
"Guidelines:",
|
|
236
|
+
"- Use task when work SHOULD be delegated to one or more specialized agents instead of handled entirely in the current session.",
|
|
237
|
+
"- Use mcp for MCP discovery first: search by capability, describe one exact tool name, then call it.",
|
|
238
|
+
"- Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)",
|
|
239
|
+
"- Be concise in your responses",
|
|
240
|
+
"- Show file paths clearly when working with files",
|
|
241
|
+
].join("\n");
|
|
242
|
+
|
|
243
|
+
const result = sanitizeAvailableToolsSection(prompt, ["bash", "grep", "mcp"]);
|
|
244
|
+
|
|
245
|
+
assert.equal(result.removed, true);
|
|
246
|
+
assert.equal(result.prompt.includes("Use task when work SHOULD"), false);
|
|
247
|
+
assert.match(result.prompt, /Use mcp for MCP discovery first/i);
|
|
248
|
+
assert.match(result.prompt, /Prefer grep\/find\/ls tools over bash/i);
|
|
249
|
+
assert.match(result.prompt, /Be concise in your responses/);
|
|
250
|
+
assert.match(result.prompt, /Show file paths clearly when working with files/);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
runTest("System prompt sanitizer removes inactive built-in write guidance", () => {
|
|
254
|
+
const prompt = [
|
|
255
|
+
"Guidelines:",
|
|
256
|
+
"- Use write only for new files or complete rewrites",
|
|
257
|
+
"- When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did",
|
|
258
|
+
"- Be concise in your responses",
|
|
259
|
+
].join("\n");
|
|
260
|
+
|
|
261
|
+
const result = sanitizeAvailableToolsSection(prompt, ["read"]);
|
|
262
|
+
|
|
263
|
+
assert.equal(result.removed, true);
|
|
264
|
+
assert.equal(result.prompt.includes("Use write only for new files or complete rewrites"), false);
|
|
265
|
+
assert.equal(result.prompt.includes("do NOT use cat or bash to display what you did"), false);
|
|
266
|
+
assert.match(result.prompt, /Be concise in your responses/);
|
|
267
|
+
});
|
|
268
|
+
|
|
210
269
|
runTest("Permission-system logger respects debug toggle and keeps review log enabled by default", () => {
|
|
211
270
|
const baseDir = mkdtempSync(join(tmpdir(), "pi-permission-system-logs-"));
|
|
212
271
|
const logsDir = join(baseDir, "logs");
|