Commit a20d843622fb

Vincent Demeester <vincent@sbr.pm>
2026-02-05 17:08:58
feat(path-validator): add filtering and verbose mode to /path-policies
Added filter argument to show subset of policies (by name, description, or action). Added --verbose/-v flag for full details. Compact mode by default shows name, status, and action on single line. Longer timeout for verbose mode (60s vs 20s). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0aa9153
Changed files (1)
dots
pi
agent
extensions
path-validator
dots/pi/agent/extensions/path-validator/index.ts
@@ -348,43 +348,81 @@ export default function (pi: ExtensionAPI) {
 
 	// Command to list policies
 	pi.registerCommand("path-policies", {
-		description: "List configured path validation policies",
-		handler: async (_args, ctx) => {
+		description: "List path policies. Usage: /path-policies [filter] [--verbose]",
+		handler: async (args, ctx) => {
 			await loadPolicies();
 			const theme = ctx.ui.theme;
 
+			// Parse arguments
+			const argStr = (args || "").trim();
+			const verbose = argStr.includes("--verbose") || argStr.includes("-v");
+			const filter = argStr.replace(/--verbose|-v/g, "").trim().toLowerCase();
+
+			// Filter policies
+			let filteredPolicies = policies;
+			if (filter) {
+				filteredPolicies = policies.filter((p) =>
+					p.name.toLowerCase().includes(filter) ||
+					p.description?.toLowerCase().includes(filter) ||
+					p.action?.toLowerCase() === filter
+				);
+			}
+
+			if (filteredPolicies.length === 0) {
+				ctx.ui.notify(`No policies matching "${filter}"`, "info");
+				return;
+			}
+
 			const widgetLines: string[] = [
-				theme.bold("๐Ÿ“‹ Path Validation Policies"),
-				theme.fg("dim", "โ”€".repeat(50)),
+				theme.bold(`๐Ÿ“‹ Path Policies${filter ? ` (${filter})` : ""} [${filteredPolicies.length}/${policies.length}]`),
+				theme.fg("dim", "โ”€".repeat(60)),
 			];
 
-			for (const policy of policies) {
-				const status = policy.enabled === false ? theme.fg("dim", "[disabled]") : theme.fg("success", "[enabled]");
+			for (const policy of filteredPolicies) {
+				const status = policy.enabled === false ? theme.fg("dim", "off") : theme.fg("success", "on");
 				const action = theme.fg(
 					policy.action === "block" ? "error" : "warning",
 					policy.action || "warn"
 				);
 
-				widgetLines.push(`${theme.fg("accent", "โ€ข")} ${theme.bold(policy.name)} ${status} ${action}`);
-				if (policy.description) {
-					widgetLines.push(`  ${theme.fg("dim", policy.description)}`);
+				// Compact: name + status + action on one line
+				widgetLines.push(`${theme.fg("accent", "โ€ข")} ${theme.bold(policy.name)} [${status}] ${action}`);
+
+				if (verbose) {
+					// Verbose: show all details
+					if (policy.description) {
+						widgetLines.push(`  ${theme.fg("dim", policy.description)}`);
+					}
+					if (policy.filenamePattern) {
+						widgetLines.push(`  ${theme.fg("dim", `Filename: ${policy.filenamePattern}`)}`);
+					}
+					if (policy.pathPattern) {
+						widgetLines.push(`  ${theme.fg("dim", `Path: ${policy.pathPattern}`)}`);
+					}
+					if (policy.requiredFilenameFormat) {
+						widgetLines.push(`  ${theme.fg("dim", `Format: ${policy.formatDescription || policy.requiredFilenameFormat}`)}`);
+					}
+					if (policy.blockedPaths?.length) {
+						widgetLines.push(`  ${theme.fg("dim", `Blocked: ${policy.blockedPaths.join(", ")}`)}`);
+					}
+					if (policy.suggestedPath) {
+						widgetLines.push(`  ${theme.fg("accent", `โ†’ ${policy.suggestedPath}`)}`);
+					}
+					widgetLines.push("");
 				}
-				if (policy.filenamePattern) {
-					widgetLines.push(`  ${theme.fg("dim", `Pattern: ${policy.filenamePattern}`)}`);
-				}
-				if (policy.suggestedPath) {
-					widgetLines.push(`  ${theme.fg("dim", `Suggest: ${policy.suggestedPath}`)}`);
-				}
-				widgetLines.push("");
 			}
 
+			if (!verbose) {
+				widgetLines.push(theme.fg("dim", "Use --verbose for details"));
+			}
 			widgetLines.push(theme.fg("dim", `Config: ${CONFIG_PATH}`));
 
 			ctx.ui.setWidget("path-policies", widgetLines);
 
+			// Longer timeout for verbose mode
 			setTimeout(() => {
 				ctx.ui.setWidget("path-policies", undefined);
-			}, 20000);
+			}, verbose ? 60000 : 20000);
 		},
 	});