@dcl-regenesislabs/opendcl 0.1.0-22237371126.commit-87c447f → 0.1.0-22239132687.commit-eccf1dd

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.
package/README.md CHANGED
@@ -32,6 +32,7 @@ The result: **more creators building more scenes, faster.**
32
32
  - **Integrated commands** — `/init` to scaffold, `/preview` to launch the dev server, `/tasks` to manage running processes, `/review` to audit code
33
33
  - **TypeScript validation** — catches type errors immediately after writing code
34
34
  - **Free 3D asset catalog** — 900+ CC0-licensed models the agent can suggest and help you use
35
+ - **Permission gate** — prompts for confirmation before destructive bash commands or writes to sensitive files
35
36
  - **Session persistence** — pick up where you left off across sessions
36
37
 
37
38
  ## Quick Start
@@ -154,7 +155,8 @@ opendcl/
154
155
  │ ├── dcl-update-check.ts # Checks npm for newer OpenDCL versions
155
156
  │ ├── dcl-validate.ts # Post-write TypeScript validation
156
157
  │ ├── dcl-tasks.ts # /tasks command (process manager)
157
- └── process-registry.ts # Shared background process registry
158
+ ├── process-registry.ts # Shared background process registry
159
+ │ └── permissions/ # Permission gate for dangerous operations
158
160
  ├── skills/ # 18 SKILL.md files (domain expertise)
159
161
  ├── prompts/ # System prompt + command templates
160
162
  ├── context/ # SDK7 reference docs + asset catalog
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ for (const ext of extensions) {
51
51
  args.push("-e", join(extDir, ext));
52
52
  }
53
53
  args.push("-e", join(extDir, "plan-mode/index.ts"));
54
+ args.push("-e", join(extDir, "permissions/index.ts"));
54
55
  // Load all skill directories
55
56
  args.push("--skill", join(packageDir, "skills"));
56
57
  // Load prompt templates (review, explain — NOT system.md since that's the system prompt)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Permission Gate Extension
3
+ *
4
+ * Prompts for confirmation before dangerous bash commands or writes to
5
+ * sensitive files. Blocks entirely in non-interactive mode.
6
+ * Disable with --no-permissions flag (for CI/container environments).
7
+ */
8
+
9
+ import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
10
+ import { classifyBashCommand, classifyFilePath } from "./utils.js";
11
+
12
+ function blockResult(reason: string, detail: string): { block: true; reason: string } {
13
+ return {
14
+ block: true,
15
+ reason: `Blocked: ${reason}\n${detail}\nUse --no-permissions to allow in non-interactive mode.`,
16
+ };
17
+ }
18
+
19
+ function denyResult(reason: string): { block: true; reason: string } {
20
+ return { block: true, reason: `User denied: ${reason}` };
21
+ }
22
+
23
+ const ALLOW = "Allow";
24
+ const ALWAYS = "Always allow";
25
+ const DENY = "Deny";
26
+
27
+ const extension: ExtensionFactory = (pi) => {
28
+ const sessionAllow = new Set<string>();
29
+
30
+ pi.registerFlag("no-permissions", {
31
+ description: "Disable permission gate (skip confirmation prompts for dangerous operations)",
32
+ type: "boolean",
33
+ default: false,
34
+ });
35
+
36
+ pi.on("tool_call", async (event, ctx) => {
37
+ if (pi.getFlag("no-permissions") === true) return;
38
+
39
+ const toolName = event.toolName as string;
40
+
41
+ if (toolName === "bash") {
42
+ const command = (event.input as { command?: string }).command ?? "";
43
+ const reason = classifyBashCommand(command);
44
+ if (!reason || sessionAllow.has(reason)) return;
45
+
46
+ if (!ctx.hasUI) return blockResult(reason, `Command: ${command}`);
47
+
48
+ const choice = await ctx.ui.select(
49
+ `${reason}\nCommand: ${command}`,
50
+ [ALLOW, ALWAYS, DENY],
51
+ );
52
+
53
+ if (choice === ALWAYS) { sessionAllow.add(reason); return; }
54
+ if (choice === ALLOW) return;
55
+ return denyResult(reason);
56
+ }
57
+
58
+ if (toolName === "write" || toolName === "edit") {
59
+ const filePath = (event.input as { path?: string }).path ?? "";
60
+ const reason = filePath ? classifyFilePath(filePath, ctx.cwd) : null;
61
+ if (!reason || sessionAllow.has(reason)) return;
62
+
63
+ if (!ctx.hasUI) return blockResult(reason, `Path: ${filePath}`);
64
+
65
+ const choice = await ctx.ui.select(
66
+ `${reason}\nFile: ${filePath}`,
67
+ [ALLOW, ALWAYS, DENY],
68
+ );
69
+
70
+ if (choice === ALWAYS) { sessionAllow.add(reason); return; }
71
+ if (choice === ALLOW) return;
72
+ return denyResult(reason);
73
+ }
74
+ });
75
+ };
76
+
77
+ export default extension;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Pure classification functions for permission gating.
3
+ * No pi dependency — extracted for testability.
4
+ */
5
+
6
+ import { resolve, relative } from "node:path";
7
+
8
+ interface DenylistEntry {
9
+ pattern: RegExp;
10
+ reason: string;
11
+ }
12
+
13
+ const DANGEROUS_BASH_PATTERNS: DenylistEntry[] = [
14
+ { pattern: /\brm\b/, reason: "Deletes files or directories" },
15
+ { pattern: /\brmdir\b/, reason: "Removes directories" },
16
+ { pattern: /\bmv\b/, reason: "Moves or renames files" },
17
+ { pattern: /\bchmod\b/, reason: "Changes file permissions" },
18
+ { pattern: /\bchown\b/, reason: "Changes file ownership" },
19
+ { pattern: /\bdd\b/, reason: "Low-level disk write" },
20
+ { pattern: /\bshred\b/, reason: "Securely deletes files" },
21
+ { pattern: /\bsudo\b/, reason: "Runs with elevated privileges" },
22
+ { pattern: /\bsu\b/, reason: "Switches user" },
23
+ { pattern: /\bkill\b/, reason: "Terminates a process" },
24
+ { pattern: /\bpkill\b/, reason: "Terminates processes by name" },
25
+ { pattern: /\bkillall\b/, reason: "Terminates all matching processes" },
26
+ { pattern: /\bgit\s+push\b/i, reason: "Pushes to a remote repository" },
27
+ { pattern: /\bgit\s+reset\b/i, reason: "Resets git state" },
28
+ { pattern: /\bgit\s+rebase\b/i, reason: "Rebases git history" },
29
+ { pattern: /\bnpm\s+install\b/i, reason: "Installs npm packages (may run postinstall scripts)" },
30
+ { pattern: /\bnpm\s+uninstall\b/i, reason: "Uninstalls npm packages" },
31
+ { pattern: /\bnpm\s+publish\b/i, reason: "Publishes to npm registry" },
32
+ { pattern: /\bcurl\b.*(-X\s*(POST|PUT|DELETE|PATCH)|--data|-d\s|-F\s|--upload)/i, reason: "Sends data via HTTP" },
33
+ { pattern: /\bssh\b/, reason: "Opens remote shell connection" },
34
+ { pattern: /\bscp\b/, reason: "Copies files to/from remote host" },
35
+ { pattern: /\breboot\b/, reason: "Reboots the system" },
36
+ { pattern: /\bshutdown\b/, reason: "Shuts down the system" },
37
+ { pattern: /\btee\b/, reason: "Writes to files via pipe" },
38
+ { pattern: /(^|\s)>(?![>&])\s*\S/, reason: "Redirects output to a file" },
39
+ { pattern: />>/, reason: "Appends output to a file" },
40
+ ];
41
+
42
+ const SENSITIVE_FILE_PATTERNS: DenylistEntry[] = [
43
+ { pattern: /\.env($|\.)/, reason: "Environment variables (may contain secrets)" },
44
+ { pattern: /\.pem$/, reason: "Private key file" },
45
+ { pattern: /\.key$/, reason: "Private key file" },
46
+ { pattern: /\.crt$/, reason: "Certificate file" },
47
+ { pattern: /credentials/i, reason: "Credentials file" },
48
+ { pattern: /\.secret/i, reason: "Secret file" },
49
+ { pattern: /(^|\/)package\.json$/, reason: "Package manifest (affects dependencies)" },
50
+ { pattern: /(^|\/)tsconfig\.json$/, reason: "TypeScript configuration" },
51
+ { pattern: /(^|\/)\.git\//, reason: "Git internal file" },
52
+ ];
53
+
54
+ function findMatchingReason(entries: DenylistEntry[], value: string): string | null {
55
+ for (const { pattern, reason } of entries) {
56
+ if (pattern.test(value)) return reason;
57
+ }
58
+ return null;
59
+ }
60
+
61
+ /**
62
+ * Returns a reason string if the command is dangerous, or null if safe.
63
+ * Callers can use the return value as both a boolean guard and a message.
64
+ */
65
+ export function classifyBashCommand(command: string): string | null {
66
+ return findMatchingReason(DANGEROUS_BASH_PATTERNS, command);
67
+ }
68
+
69
+ /**
70
+ * Returns a reason string if the file path is sensitive or outside the
71
+ * project root, or null if safe.
72
+ */
73
+ export function classifyFilePath(filePath: string, projectRoot: string): string | null {
74
+ const resolved = resolve(projectRoot, filePath);
75
+ const rel = relative(projectRoot, resolved);
76
+
77
+ if (rel.startsWith("..")) {
78
+ return "File is outside the project root";
79
+ }
80
+
81
+ return findMatchingReason(SENSITIVE_FILE_PATTERNS, filePath);
82
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl-regenesislabs/opendcl",
3
- "version": "0.1.0-22237371126.commit-87c447f",
3
+ "version": "0.1.0-22239132687.commit-eccf1dd",
4
4
  "description": "AI coding assistant for Decentraland SDK7 scene development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,5 +61,5 @@
61
61
  "prompts/",
62
62
  "context/"
63
63
  ],
64
- "commit": "87c447f3a7cbb92fd2dced062e437db0953a91d5"
64
+ "commit": "eccf1ddf7568056584700b927142426e95be390d"
65
65
  }