@bacnh85/pi-plan 0.1.3 → 0.1.5
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/README.md +1 -1
- package/index.ts +13 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Pi extension that adds a lightweight plan mode inspired by Codex and Claude Code
|
|
|
4
4
|
|
|
5
5
|
- Toggle plan mode with `/plan` or `Ctrl+Alt+P`.
|
|
6
6
|
- Remembers separate thinking/reasoning levels for planning and normal execution across sessions based on the active mode when you change Pi's reasoning level.
|
|
7
|
-
- Keeps planning read-only by
|
|
7
|
+
- Keeps planning read-only by limiting active tools to planning-safe tools and blocking destructive shell commands.
|
|
8
8
|
- Provides a `write_plan` tool so the agent writes reviewable Markdown plans into `.agents/plans/` in the current workspace.
|
|
9
9
|
- Provides an `ask_plan_question` tool so the agent can ask selection-style clarifying questions during planning, with an option for free-form user input.
|
|
10
10
|
- Prompts after a plan is written so you can approve execution, approve only, keep planning, or refine with feedback.
|
package/index.ts
CHANGED
|
@@ -11,8 +11,8 @@ const PLAN_TOOL = "write_plan";
|
|
|
11
11
|
const PLAN_QUESTION_TOOL = "ask_plan_question";
|
|
12
12
|
const PLAN_EXECUTE_COMMAND = "plan-execute";
|
|
13
13
|
const PREFERENCES_FILE = path.join(os.homedir(), ".pi", "agent", "pi-plan", "preferences.json");
|
|
14
|
-
const PLAN_MODE_DISABLED_TOOLS = new Set(["edit", "write"]);
|
|
15
14
|
const DEFAULT_PLAN_TOOLS = ["read", "bash", "grep", "find", "ls", PLAN_TOOL, PLAN_QUESTION_TOOL];
|
|
15
|
+
const PLAN_ALLOWED_TOOLS = new Set(DEFAULT_PLAN_TOOLS);
|
|
16
16
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
17
17
|
|
|
18
18
|
type ThinkingLevel = (typeof THINKING_LEVELS)[number];
|
|
@@ -152,6 +152,13 @@ function isDestructiveBash(command: string): boolean {
|
|
|
152
152
|
return DESTRUCTIVE_BASH_PATTERNS.some((pattern) => pattern.test(command));
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
function isReadOnlyBash(command: string): boolean {
|
|
156
|
+
const trimmed = command.trim();
|
|
157
|
+
if (!trimmed) return true;
|
|
158
|
+
if (/[;&|`$(){}]/.test(trimmed) || /\b(python|python3|node|ruby|perl|php|sh|bash|zsh|fish)\b/i.test(trimmed)) return false;
|
|
159
|
+
return /^(git\s+(status|branch|rev-parse|diff|show|log|ls-files)\b|(?:rg|grep|find|fd|ls|pwd|cat|head|tail|sed|awk|wc|sort|uniq|cut)\b)/i.test(trimmed);
|
|
160
|
+
}
|
|
161
|
+
|
|
155
162
|
export default function piPlanExtension(pi: ExtensionAPI): void {
|
|
156
163
|
let planModeEnabled = false;
|
|
157
164
|
let executionMode = false;
|
|
@@ -199,7 +206,7 @@ export default function piPlanExtension(pi: ExtensionAPI): void {
|
|
|
199
206
|
function enablePlanTools(): void {
|
|
200
207
|
const baseline = toolsBeforePlan ?? pi.getActiveTools();
|
|
201
208
|
toolsBeforePlan = baseline;
|
|
202
|
-
pi.setActiveTools(unique([...baseline.filter((tool) =>
|
|
209
|
+
pi.setActiveTools(unique([...baseline.filter((tool) => PLAN_ALLOWED_TOOLS.has(tool)), ...DEFAULT_PLAN_TOOLS]));
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
function restoreTools(): void {
|
|
@@ -484,12 +491,12 @@ export default function piPlanExtension(pi: ExtensionAPI): void {
|
|
|
484
491
|
|
|
485
492
|
pi.on("tool_call", async (event) => {
|
|
486
493
|
if (!planModeEnabled) return;
|
|
487
|
-
if (
|
|
488
|
-
return { block: true, reason: `pi-plan: ${event.toolName} is disabled
|
|
494
|
+
if (!PLAN_ALLOWED_TOOLS.has(event.toolName)) {
|
|
495
|
+
return { block: true, reason: `pi-plan: ${event.toolName} is disabled in read-only plan mode. Use ${PLAN_TOOL} to write the plan file.` };
|
|
489
496
|
}
|
|
490
497
|
if (!isToolCallEventType("bash", event)) return;
|
|
491
|
-
if (isDestructiveBash(event.input.command)) {
|
|
492
|
-
return { block: true, reason: `pi-plan: bash command blocked in plan mode because
|
|
498
|
+
if (isDestructiveBash(event.input.command) || !isReadOnlyBash(event.input.command)) {
|
|
499
|
+
return { block: true, reason: `pi-plan: bash command blocked in plan mode because only simple read-only inspection commands are allowed.\nCommand: ${event.input.command}` };
|
|
493
500
|
}
|
|
494
501
|
});
|
|
495
502
|
|