gentle-pi 0.1.12 → 0.1.13

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.
Binary file
@@ -102,7 +102,7 @@ const CUSTOM_MODEL = "Custom model id";
102
102
 
103
103
  const MODEL_CONTROL_OPTIONS = [KEEP_CURRENT, INHERIT_MODEL, CUSTOM_MODEL] as const;
104
104
 
105
- function evaluateCommand(command: string): ToolCallEventResult | undefined {
105
+ function evaluateDeniedCommand(command: string): ToolCallEventResult | undefined {
106
106
  for (const pattern of DENIED_BASH_PATTERNS) {
107
107
  if (pattern.test(command)) {
108
108
  return {
@@ -111,17 +111,32 @@ function evaluateCommand(command: string): ToolCallEventResult | undefined {
111
111
  };
112
112
  }
113
113
  }
114
- for (const pattern of CONFIRM_BASH_PATTERNS) {
115
- if (pattern.test(command)) {
116
- return {
117
- block: true,
118
- reason: "Gentle AI safety policy requires explicit user approval before this command.",
119
- };
120
- }
121
- }
122
114
  return undefined;
123
115
  }
124
116
 
117
+ function commandRequiresConfirmation(command: string): boolean {
118
+ return CONFIRM_BASH_PATTERNS.some((pattern) => pattern.test(command));
119
+ }
120
+
121
+ async function confirmCommand(command: string, ctx: ExtensionContext): Promise<ToolCallEventResult | undefined> {
122
+ const denied = evaluateDeniedCommand(command);
123
+ if (denied) return denied;
124
+ if (!commandRequiresConfirmation(command)) return undefined;
125
+ if (!ctx.hasUI) {
126
+ return {
127
+ block: true,
128
+ reason: "Gentle AI safety policy requires interactive confirmation before this command.",
129
+ };
130
+ }
131
+ const preview = truncateToWidth(command.replace(/\s+/g, " ").trim(), 180, "…");
132
+ const approved = await ctx.ui.confirm("Allow guarded command?", preview);
133
+ if (approved) return undefined;
134
+ return {
135
+ block: true,
136
+ reason: "Gentle AI safety policy blocked the command because it was not confirmed.",
137
+ };
138
+ }
139
+
125
140
  function copyDirectoryFiles(sourceDir: string, targetDir: string, force: boolean): { copied: number; skipped: number } {
126
141
  if (!existsSync(sourceDir)) return { copied: 0, skipped: 0 };
127
142
  mkdirSync(targetDir, { recursive: true });
@@ -594,9 +609,9 @@ export default function gentleAi(pi: ExtensionAPI): void {
594
609
  systemPrompt: `${event.systemPrompt}\n\n${buildGentlePrompt(readPersonaMode(ctx.cwd))}`,
595
610
  }));
596
611
 
597
- pi.on("tool_call", (event) => {
612
+ pi.on("tool_call", async (event, ctx) => {
598
613
  if (event.toolName !== "bash") return undefined;
599
- return evaluateCommand(event.input.command);
614
+ return confirmCommand(event.input.command, ctx);
600
615
  });
601
616
 
602
617
  pi.registerCommand("gentle-ai:install-sdd", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gentle-pi",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Opinionated el Gentleman harness package for Pi: SDD/OpenSpec workflow, strict TDD guidance, subagent assets, and safety defaults.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,6 +26,7 @@
26
26
  "README.md"
27
27
  ],
28
28
  "pi": {
29
+ "image": "https://raw.githubusercontent.com/Gentleman-Programming/gentle-pi/main/pi-packages/gentle-ai/assets/gentle-logo-only.png",
29
30
  "extensions": [
30
31
  "./extensions"
31
32
  ],