Skip to content

Commit b572b1c

Browse files
backnotpropclaude
andcommitted
refactor(pi-extension): remove bash regex gating, use prompt-based guidance
Delete DESTRUCTIVE_PATTERNS and isDestructiveCommand() from utils.ts. Remove bash interception from tool_call handler. Bash is now unrestricted during planning — the system prompt guides the agent not to run destructive commands. Write/edit file restrictions to the plan file remain enforced. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5fe8fc8 commit b572b1c

File tree

3 files changed

+9
-48
lines changed

3 files changed

+9
-48
lines changed

apps/pi-extension/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ The extension manages a state machine: **idle** → **planning** → **executing
104104

105105
During **planning**:
106106
- All tools from other extensions remain available
107-
- Bash blocks destructive commands (rm, git push, npm install, etc.) but allows read-only and web fetching (curl, wget)
107+
- Bash is unrestricted — the agent is guided by the system prompt not to run destructive commands
108108
- Writes and edits restricted to the plan file only
109109

110110
During **executing**:

apps/pi-extension/index.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* - /plannotator command or Ctrl+Alt+P to toggle
1111
* - --plan flag to start in planning mode
1212
* - --plan-file flag to customize the plan file path
13-
* - Bash restricted (destructive commands blocked) during planning
13+
* - Bash unrestricted during planning (prompt-guided)
1414
* - Write restricted to plan file only during planning
1515
* - exit_plan_mode tool with browser-based visual approval
1616
* - [DONE:n] markers for execution progress tracking
@@ -26,7 +26,7 @@ import type { AssistantMessage, TextContent } from "@mariozechner/pi-ai";
2626
import { Type } from "@mariozechner/pi-ai";
2727
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
2828
import { Key } from "@mariozechner/pi-tui";
29-
import { isDestructiveCommand, markCompletedSteps, parseChecklist, type ChecklistItem } from "./utils.js";
29+
import { markCompletedSteps, parseChecklist, type ChecklistItem } from "./utils.js";
3030
import {
3131
startPlanReviewServer,
3232
startReviewServer,
@@ -76,7 +76,7 @@ export default function plannotator(pi: ExtensionAPI): void {
7676
// ── Flags ────────────────────────────────────────────────────────────
7777

7878
pi.registerFlag("plan", {
79-
description: "Start in plan mode (read-only exploration)",
79+
description: "Start in plan mode (restricted exploration and planning)",
8080
type: "boolean",
8181
default: false,
8282
});
@@ -451,20 +451,10 @@ export default function plannotator(pi: ExtensionAPI): void {
451451

452452
// ── Event Handlers ───────────────────────────────────────────────────
453453

454-
// Gate writes and bash during planning
454+
// Gate writes during planning
455455
pi.on("tool_call", async (event, ctx) => {
456456
if (phase !== "planning") return;
457457

458-
if (event.toolName === "bash") {
459-
const command = event.input.command as string;
460-
if (isDestructiveCommand(command)) {
461-
return {
462-
block: true,
463-
reason: `Plannotator: destructive command blocked during planning.\nCommand: ${command}`,
464-
};
465-
}
466-
}
467-
468458
if (event.toolName === "write") {
469459
const targetPath = resolve(ctx.cwd, event.input.path as string);
470460
const allowedPath = resolvePlanPath(ctx.cwd);
@@ -497,7 +487,9 @@ export default function plannotator(pi: ExtensionAPI): void {
497487
content: `[PLANNOTATOR - PLANNING PHASE]
498488
You are in plan mode. You MUST NOT make any changes to the codebase — no edits, no commits, no installs, no destructive commands. The ONLY file you may write to or edit is the plan file: ${planFilePath}.
499489
500-
Available tools: read, bash (destructive commands are blocked; curl/wget for web fetching is allowed), grep, find, ls, write (${planFilePath} only), edit (${planFilePath} only), exit_plan_mode
490+
Available tools: read, bash, grep, find, ls, write (${planFilePath} only), edit (${planFilePath} only), exit_plan_mode
491+
492+
Do not run destructive bash commands (rm, git push, npm install, etc.) — focus on reading and exploring the codebase. Web fetching (curl, wget) is fine.
501493
502494
## Iterative Planning Workflow
503495

apps/pi-extension/utils.ts

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,10 @@
11
/**
22
* Plannotator Pi extension utilities.
33
*
4-
* Inlined versions of bash safety checks and checklist parsing.
4+
* Checklist parsing and progress tracking helpers.
55
* (No access to pi-mono's plan-mode/utils at runtime.)
66
*/
77

8-
// ── Bash Safety ──────────────────────────────────────────────────────────
9-
10-
const DESTRUCTIVE_PATTERNS = [
11-
/\brm\b/i, /\brmdir\b/i, /\bmv\b/i, /\bcp\b/i, /\bmkdir\b/i,
12-
/\btouch\b/i, /\bchmod\b/i, /\bchown\b/i, /\bchgrp\b/i, /\bln\b/i,
13-
/\btee\b/i, /\btruncate\b/i, /\bdd\b/i, /\bshred\b/i,
14-
/(^|[^<])>(?!>)/, />>/,
15-
/\bnpm\s+(install|uninstall|update|ci|link|publish)/i,
16-
/\byarn\s+(add|remove|install|publish)/i,
17-
/\bpnpm\s+(add|remove|install|publish)/i,
18-
/\bpip\s+(install|uninstall)/i,
19-
/\bapt(-get)?\s+(install|remove|purge|update|upgrade)/i,
20-
/\bbrew\s+(install|uninstall|upgrade)/i,
21-
/\bgit\s+(add|commit|push|pull|merge|rebase|reset|checkout|branch\s+-[dD]|stash|cherry-pick|revert|tag|init|clone)/i,
22-
/\bsudo\b/i, /\bsu\b/i, /\bkill\b/i, /\bpkill\b/i, /\bkillall\b/i,
23-
/\breboot\b/i, /\bshutdown\b/i,
24-
/\bsystemctl\s+(start|stop|restart|enable|disable)/i,
25-
/\bservice\s+\S+\s+(start|stop|restart)/i,
26-
/\b(vim?|nano|emacs|code|subl)\b/i,
27-
];
28-
29-
export function isDestructiveCommand(command: string): boolean {
30-
// Strip safe fd redirects so `curl ... 2>/dev/null` and `2>&1` pass
31-
const normalized = command
32-
.replace(/\s+\d*>\s*\/dev\/null/g, "")
33-
.replace(/\s+\d*>&\d+/g, "")
34-
.replace(/\s+&>\s*\/dev\/null/g, "");
35-
36-
return DESTRUCTIVE_PATTERNS.some((p) => p.test(normalized));
37-
}
38-
398
// ── Checklist Parsing ────────────────────────────────────────────────────
409

4110
export interface ChecklistItem {

0 commit comments

Comments
 (0)