@bacnh85/pi-plan 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/index.ts +33 -8
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -181,6 +181,26 @@ function tokenizeSimpleCommand(command: string): string[] | undefined {
181
181
  return trimmed.split(/\s+/).filter(Boolean);
182
182
  }
183
183
 
184
+ function sanitizeCommand(command: string): string[] {
185
+ let sanitized = command;
186
+
187
+ // Strip /dev/null redirects: 2>/dev/null, >/dev/null, >>/dev/null, &>/dev/null
188
+ sanitized = sanitized.replace(/\d*>>?\s*\/dev\/null/g, "");
189
+ sanitized = sanitized.replace(/&>\s*\/dev\/null/g, "");
190
+ // Strip fd redirections: 2>&1, 1>&2, etc.
191
+ sanitized = sanitized.replace(/\s*\d*>&\d+\s*/g, " ");
192
+
193
+ // Strip cd <path> && / cd <path> ; prefix
194
+ sanitized = sanitized.replace(/^cd\s+(?:"[^"]*"|'[^']*'|[^\s;&|]+)\s*(?:&&|;)\s*/i, "").trim();
195
+
196
+ // If command contains pipes, split into segments and validate each
197
+ if (sanitized.includes("|")) {
198
+ return sanitized.split("|").map((s) => s.trim()).filter(Boolean);
199
+ }
200
+
201
+ return [sanitized.trim()];
202
+ }
203
+
184
204
  function hasOptionValue(tokens: string[], index: number): boolean {
185
205
  return index + 1 < tokens.length && !tokens[index + 1].startsWith("-");
186
206
  }
@@ -219,14 +239,19 @@ function isAllowedGitCommand(tokens: string[]): boolean {
219
239
  }
220
240
 
221
241
  export function isReadOnlyBash(command: string): boolean {
222
- const tokens = tokenizeSimpleCommand(command);
223
- if (!tokens) return false;
224
- if (tokens.length === 0) return true;
225
- const normalized = tokens[0] === "rtk" ? tokens.slice(1) : tokens;
226
- if (normalized.length === 0) return false;
227
- if (isAllowedGitCommand(normalized)) return true;
228
- if (isAllowedNpmMetadataCommand(normalized)) return true;
229
- return /^(rg|grep|find|fd|ls|pwd|cat|head|tail|sed|awk|wc|sort|uniq|cut)$/.test(normalized[0]);
242
+ const segments = sanitizeCommand(command);
243
+ if (segments.length === 0) return true;
244
+
245
+ return segments.every((segment) => {
246
+ const tokens = tokenizeSimpleCommand(segment);
247
+ if (!tokens) return false;
248
+ if (tokens.length === 0) return true;
249
+ const normalized = tokens[0] === "rtk" ? tokens.slice(1) : tokens;
250
+ if (normalized.length === 0) return false;
251
+ if (isAllowedGitCommand(normalized)) return true;
252
+ if (isAllowedNpmMetadataCommand(normalized)) return true;
253
+ return /^(rg|grep|find|fd|ls|pwd|cat|head|tail|sed|awk|wc|sort|uniq|cut|read)$/.test(normalized[0]);
254
+ });
230
255
  }
231
256
 
232
257
  export default function piPlanExtension(pi: ExtensionAPI): void {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-plan",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Pi extension that adds a plan mode with workspace markdown plans and thinking-level presets.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {