Skip to content

Instantly share code, notes, and snippets.

@sigmaSd
Last active June 21, 2025 14:52
Show Gist options
  • Save sigmaSd/8a08b2f4dfe971c804a969b482965cb4 to your computer and use it in GitHub Desktop.
Save sigmaSd/8a08b2f4dfe971c804a969b482965cb4 to your computer and use it in GitHub Desktop.
random script to make deno permission dialog apper as a gui popup
/**
* GUI Permission Dialog for Deno
*
* Runs a Deno script and shows permission prompts as GUI dialogs
* instead of CLI prompts.
*
* Usage:
* deno run -A gui-permissions.ts my-script.ts
*/
import { Pty } from "jsr:@sigma/[email protected]";
import { stripAnsiCode } from "jsr:@std/[email protected]/colors";
async function showDialog(message: string): Promise<boolean> {
const os = Deno.build.os;
try {
let command: string[];
switch (os) {
case "linux":
// Try zenity first, then kdialog as fallback
command = [
"zenity",
"--question",
"--text",
message,
"--title",
"Deno Permission Request",
"--width",
"400",
"--height",
"200",
];
break;
case "darwin": {
// macOS using osascript with better formatting
const script = `display dialog "${
message.replace(/"/g, '\\"').replace(/\n/g, "\\n")
}" with title "Deno Permission Request" buttons {"Deny", "Allow"} default button "Allow" with icon caution`;
command = ["osascript", "-e", script];
break;
}
case "windows": {
// Windows using PowerShell with better formatting
const psScript =
`Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('${
message.replace(/'/g, "''").replace(/\n/g, "`n")
}', 'Deno Permission Request', 'YesNo', 'Question') -eq 'Yes'`;
command = ["powershell", "-Command", psScript];
break;
}
default:
console.error(`Unsupported OS: ${os}`);
return false;
}
const process = new Deno.Command(command[0], {
args: command.slice(1),
stdout: "piped",
stderr: "piped",
});
const { code, stdout } = await process.output();
if (os === "windows") {
const output = new TextDecoder().decode(stdout).trim();
return output === "True";
} else if (os === "darwin") {
// osascript returns 0 for "Allow", 1 for "Deny"
return code === 0;
} else {
// zenity returns 0 for "Yes", 1 for "No"
return code === 0;
}
} catch (error) {
console.error("Failed to show dialog:", error);
// Fallback to console prompt
return await showConsolePrompt(message);
}
}
async function showConsolePrompt(message: string): Promise<boolean> {
console.log("\n" + message);
console.log("Allow? (y/N): ");
const buf = new Uint8Array(1024);
const n = await Deno.stdin.read(buf);
if (n === null) return false;
const input = new TextDecoder().decode(buf.subarray(0, n)).trim()
.toLowerCase();
return input === "y" || input === "yes";
}
function extractPermissionMessage(lines: string): string | null {
// Look for the most detailed permission request patterns
const fullPattern =
/┏ ⚠️\s+Deno requests (.*?)\n┠─ Requested by `(.*?)` API\.(.*?)┗/s;
const fullMatch = lines.match(fullPattern);
if (fullMatch) {
const permission = fullMatch[1].trim();
const api = fullMatch[2].trim();
const additionalInfo = fullMatch[3].trim();
let message = `🔒 DENO PERMISSION REQUEST\n\n`;
message += `Permission: ${permission}\n`;
message += `API: ${api}\n`;
if (additionalInfo) {
// Clean up additional info
const cleanInfo = additionalInfo
.replace(/┠─/g, "")
.replace(/│/g, "")
.replace(/\s+/g, " ")
.trim();
if (cleanInfo) {
// too verbose
// message += `Details: ${cleanInfo}\n`;
}
}
message += `\nAllow this permission?`;
return message;
}
// Look for detailed permission request patterns (without additional info)
const detailedPattern =
/┏ ⚠️\s+Deno requests (.*?)\n┠─ Requested by `(.*?)` API\./s;
const match = lines.match(detailedPattern);
if (match) {
const permission = match[1].trim();
const api = match[2].trim();
return `🔒 DENO PERMISSION REQUEST\n\nPermission: ${permission}\nAPI: ${api}\n\nAllow this permission?`;
}
// Look for simpler permission patterns with box drawing
const simplePattern = /┏ ⚠️.*?Deno requests (.*?)\./s;
const simpleMatch = lines.match(simplePattern);
if (simpleMatch) {
const permission = simpleMatch[1].trim();
return `🔒 DENO PERMISSION REQUEST\n\nPermission: ${permission}\n\nAllow this permission?`;
}
// Legacy pattern fallback
const legacyPattern = /┌ ⚠️.*?\n│\s*(.*?)\n│.*?Allow\?/s;
const legacyMatch = lines.match(legacyPattern);
if (legacyMatch) {
return `🔒 DENO PERMISSION REQUEST\n\n${
legacyMatch[1].trim()
}\n\nAllow this permission?`;
}
return null;
}
if (import.meta.main) {
if (Deno.args.length === 0) {
console.error(
"Usage: deno run -A gui-permissions.ts <script.ts> [args...]",
);
Deno.exit(1);
}
console.log("Starting Deno script with GUI permission dialog...");
const pty = new Pty(Deno.execPath(), {
args: ["run", ...Deno.args],
env: { NO_COLOR: "1" },
});
let buffer = "";
pty.setPollingInterval(100);
for await (const chunk of pty.readable) {
const cleaned = stripAnsiCode(chunk);
buffer += cleaned;
// Print output to console (except permission prompts)
if (!cleaned.includes("Allow?")) {
await Deno.stdout.write(new TextEncoder().encode(cleaned));
}
// Check for permission prompts
if (buffer.includes("Allow?")) {
console.log("\n🔍 DEBUG: Raw buffer content:");
console.log("=" + "=".repeat(50));
console.log(buffer);
console.log("=" + "=".repeat(50));
const message = extractPermissionMessage(buffer);
if (message) {
console.log("\n🔒 Permission request detected...");
console.log("📋 Extracted message:", message);
const allowed = await showDialog(message);
if (allowed) {
console.log("✅ Permission granted");
pty.write("y\n");
} else {
console.log("❌ Permission denied");
pty.write("n\n");
}
} else {
throw new Error(
"Could not extract permission message from Deno output",
);
}
// Clear buffer after handling prompt
buffer = "";
}
// Keep buffer manageable
if (buffer.length > 10000) {
buffer = buffer.slice(-5000);
}
}
console.log("\nScript execution completed.");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment