@dcl-regenesislabs/opendcl 0.1.4-22337368589.commit-8d0fe5a → 0.1.4-22626562583.commit-09a1d03
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 +1 -1
- package/context/asset-packs-catalog.md +5 -3
- package/context/audio-catalog.md +5 -3
- package/context/open-source-3d-assets.md +9 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/extensions/dcl-asset-path.ts +60 -0
- package/extensions/permissions/index.ts +56 -25
- package/extensions/permissions/utils.ts +15 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -32,7 +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 asset catalogs** — 2,700+ Creator Hub 3D models, 900+ CC0-licensed models, and 50 audio files the agent proactively suggests when building scenes
|
|
35
|
-
- **Permission gate** — prompts for confirmation before destructive bash commands
|
|
35
|
+
- **Permission gate** — prompts for confirmation before destructive bash commands, writes to sensitive files, or any file access outside the working directory
|
|
36
36
|
- **Compact tool output** — write shows path + size instead of file content, read shows a 5-line preview instead of 10
|
|
37
37
|
- **Session persistence** — pick up where you left off across sessions
|
|
38
38
|
|
|
@@ -6,10 +6,12 @@ Premium 3D models from the official Decentraland Creator Hub. All models are fre
|
|
|
6
6
|
|
|
7
7
|
**How to use**:
|
|
8
8
|
1. Find a model below that matches your scene
|
|
9
|
-
2. Download it
|
|
10
|
-
|
|
9
|
+
2. Download it — the output path **must** start with `models/`:
|
|
10
|
+
`curl -o models/<filename>.glb "<URL>"`
|
|
11
|
+
3. Reference it: `GltfContainer.create(entity, { src: 'models/<filename>.glb' })`
|
|
11
12
|
|
|
12
|
-
> **Important**:
|
|
13
|
+
> **Important**: Always download into `models/`. Never write to the scene root.
|
|
14
|
+
> Correct: `curl -o models/Sofa_Black.glb "..."` | Wrong: `curl -o Sofa_Black.glb "..."`
|
|
13
15
|
|
|
14
16
|
---
|
|
15
17
|
|
package/context/audio-catalog.md
CHANGED
|
@@ -6,10 +6,12 @@ Free audio files from the official Decentraland Creator Hub asset packs. All sou
|
|
|
6
6
|
|
|
7
7
|
**How to use**:
|
|
8
8
|
1. Find a sound below that matches your scene
|
|
9
|
-
2. Download it
|
|
10
|
-
|
|
9
|
+
2. Download it — the output path **must** start with `sounds/`:
|
|
10
|
+
`curl -o sounds/<filename>.mp3 "<URL>"`
|
|
11
|
+
3. Reference it: `AudioSource.create(entity, { audioClipUrl: 'sounds/<filename>.mp3', playing: true, loop: false })`
|
|
11
12
|
|
|
12
|
-
> **Important**:
|
|
13
|
+
> **Important**: Always download into `sounds/`. Never write to the scene root.
|
|
14
|
+
> Correct: `curl -o sounds/click.mp3 "..."` | Wrong: `curl -o click.mp3 "..."`
|
|
13
15
|
|
|
14
16
|
---
|
|
15
17
|
|
|
@@ -9,6 +9,15 @@ Free CC0-licensed GLB 3D models curated from the [Open Source 3D Assets](https:/
|
|
|
9
9
|
- **Creator**: Polygonal Mind
|
|
10
10
|
- **License**: CC0 (Public Domain)
|
|
11
11
|
|
|
12
|
+
**How to use**:
|
|
13
|
+
1. Find a model below that matches your scene
|
|
14
|
+
2. Download it — the output path **must** start with `models/`:
|
|
15
|
+
`curl -o models/<filename>.glb "<URL>"`
|
|
16
|
+
3. Reference it: `GltfContainer.create(entity, { src: 'models/<filename>.glb' })`
|
|
17
|
+
|
|
18
|
+
> **Important**: Always download into `models/`. Never write to the scene root.
|
|
19
|
+
> Correct: `curl -o models/Tree_01.glb "..."` | Wrong: `curl -o Tree_01.glb "..."`
|
|
20
|
+
|
|
12
21
|
Base URL for all downloads:
|
|
13
22
|
```
|
|
14
23
|
https://raw.githubusercontent.com/ToxSam/cc0-models-Polygonal-Mind/main/projects/
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAEzC,uFAAuF;AACvF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AACtD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,QAAQ,CAAC;AAC7C,CAAC;AAED,wEAAwE;AACxE,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;AACrD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3F,CAAC;AAED,yCAAyC;AACzC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,wFAAwF;AACxF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,GAAG;SACrB,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC;SACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;SAC9E,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAC7C,CAAC;AAED,sBAAsB;AACtB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,eAAe;IACf,cAAc;IACd,qBAAqB;IACrB,iBAAiB;IACjB,eAAe;IACf,qBAAqB;IACrB,eAAe;IACf,cAAc;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset Path Guard Extension
|
|
3
|
+
*
|
|
4
|
+
* Blocks curl downloads that place asset files in the wrong directory.
|
|
5
|
+
* Models (.glb/.gltf) must go into models/, audio (.mp3/.ogg/.wav) into sounds/.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
|
|
9
|
+
|
|
10
|
+
interface AssetViolation {
|
|
11
|
+
file: string;
|
|
12
|
+
expected: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ASSET_RULES: { pattern: RegExp; dir: string }[] = [
|
|
16
|
+
{ pattern: /\.gl(?:b|tf)$/i, dir: "models/" },
|
|
17
|
+
{ pattern: /\.(?:mp3|ogg|wav)$/i, dir: "sounds/" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check a curl command for asset files downloaded to the wrong directory.
|
|
22
|
+
* Returns null if the command is fine, or a violation object if it should be blocked.
|
|
23
|
+
*/
|
|
24
|
+
export function checkCurlOutput(command: string): AssetViolation | null {
|
|
25
|
+
const outputMatches = command.matchAll(/-o\s+["']?([^\s"']+)/g);
|
|
26
|
+
for (const match of outputMatches) {
|
|
27
|
+
const outputPath = match[1];
|
|
28
|
+
for (const rule of ASSET_RULES) {
|
|
29
|
+
if (rule.pattern.test(outputPath) && !outputPath.includes(rule.dir)) {
|
|
30
|
+
const relativePath = outputPath.replace(/^\.\//, "");
|
|
31
|
+
return {
|
|
32
|
+
file: relativePath,
|
|
33
|
+
expected: rule.dir + relativePath,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const extension: ExtensionFactory = (pi) => {
|
|
42
|
+
pi.on("tool_call", async (event) => {
|
|
43
|
+
if (event.toolName !== "bash") return;
|
|
44
|
+
|
|
45
|
+
const command = (event.input as { command?: string }).command ?? "";
|
|
46
|
+
const violation = checkCurlOutput(command);
|
|
47
|
+
if (!violation) return;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
block: true,
|
|
51
|
+
reason: [
|
|
52
|
+
"Asset files must be downloaded into the correct directory.",
|
|
53
|
+
`Use: curl -o ${violation.expected} instead of curl -o ${violation.file}`,
|
|
54
|
+
"Models (.glb/.gltf) → models/ Audio (.mp3/.ogg/.wav) → sounds/",
|
|
55
|
+
].join("\n"),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default extension;
|
|
@@ -7,25 +7,53 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
|
|
10
|
-
import { classifyBashCommand, classifyFilePath } from "./utils.js";
|
|
10
|
+
import { classifyBashCommand, classifyFilePath, isOutsideCwd, OUTSIDE_CWD_REASON } from "./utils.js";
|
|
11
|
+
import { resolve } from "node:path";
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
type BlockResult = { block: true; reason: string };
|
|
14
|
+
|
|
15
|
+
function blockResult(reason: string, detail: string): BlockResult {
|
|
13
16
|
return {
|
|
14
17
|
block: true,
|
|
15
18
|
reason: `Blocked: ${reason}\n${detail}\nUse --no-permissions to allow in non-interactive mode.`,
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
function denyResult(reason: string):
|
|
22
|
+
function denyResult(reason: string): BlockResult {
|
|
20
23
|
return { block: true, reason: `User denied: ${reason}` };
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
const
|
|
24
|
-
const ALWAYS = "Always allow";
|
|
25
|
-
const DENY = "Deny";
|
|
26
|
+
const CHOICES = ["Allow", "Always allow", "Deny"] as const;
|
|
26
27
|
|
|
27
28
|
const extension: ExtensionFactory = (pi) => {
|
|
28
29
|
const sessionAllow = new Set<string>();
|
|
30
|
+
const allowedPaths = new Set<string>();
|
|
31
|
+
|
|
32
|
+
function isPathAllowed(resolvedPath: string): boolean {
|
|
33
|
+
for (const allowed of allowedPaths) {
|
|
34
|
+
if (resolvedPath === allowed || resolvedPath.startsWith(allowed + "/")) return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Prompts the user for confirmation and handles their choice.
|
|
41
|
+
* Returns a BlockResult to deny, or undefined to allow.
|
|
42
|
+
*/
|
|
43
|
+
async function promptOrBlock(
|
|
44
|
+
ctx: { hasUI: boolean; ui: { select: (title: string, options: string[]) => Promise<string | null> } },
|
|
45
|
+
reason: string,
|
|
46
|
+
detail: string,
|
|
47
|
+
onAlways: () => void,
|
|
48
|
+
): Promise<BlockResult | undefined> {
|
|
49
|
+
if (!ctx.hasUI) return blockResult(reason, detail);
|
|
50
|
+
|
|
51
|
+
const choice = await ctx.ui.select(`${reason}\n${detail}`, [...CHOICES]);
|
|
52
|
+
|
|
53
|
+
if (choice === "Always allow") { onAlways(); return; }
|
|
54
|
+
if (choice === "Allow") return;
|
|
55
|
+
return denyResult(reason);
|
|
56
|
+
}
|
|
29
57
|
|
|
30
58
|
pi.registerFlag("no-permissions", {
|
|
31
59
|
description: "Disable permission gate (skip confirmation prompts for dangerous operations)",
|
|
@@ -43,33 +71,36 @@ const extension: ExtensionFactory = (pi) => {
|
|
|
43
71
|
const reason = classifyBashCommand(command);
|
|
44
72
|
if (!reason || sessionAllow.has(reason)) return;
|
|
45
73
|
|
|
46
|
-
|
|
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);
|
|
74
|
+
return promptOrBlock(ctx, reason, `Command: ${command}`, () => sessionAllow.add(reason));
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
if (toolName === "write" || toolName === "edit") {
|
|
59
78
|
const filePath = (event.input as { path?: string }).path ?? "";
|
|
60
79
|
const reason = filePath ? classifyFilePath(filePath, ctx.cwd) : null;
|
|
61
|
-
if (!reason
|
|
80
|
+
if (!reason) return;
|
|
62
81
|
|
|
63
|
-
if (
|
|
82
|
+
if (reason === OUTSIDE_CWD_REASON) {
|
|
83
|
+
const resolved = resolve(ctx.cwd, filePath);
|
|
84
|
+
if (isPathAllowed(resolved)) return;
|
|
85
|
+
|
|
86
|
+
return promptOrBlock(ctx, reason, `File: ${filePath}`, () => allowedPaths.add(resolved));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (sessionAllow.has(reason)) return;
|
|
90
|
+
|
|
91
|
+
return promptOrBlock(ctx, reason, `Path: ${filePath}`, () => sessionAllow.add(reason));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (toolName === "read" || toolName === "grep" || toolName === "find" || toolName === "ls") {
|
|
95
|
+
const filePath = (event.input as { path?: string }).path ?? "";
|
|
96
|
+
if (!filePath) return;
|
|
64
97
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
98
|
+
const resolved = resolve(ctx.cwd, filePath);
|
|
99
|
+
const reason = isOutsideCwd(filePath, ctx.cwd);
|
|
100
|
+
if (!reason) return;
|
|
101
|
+
if (isPathAllowed(resolved)) return;
|
|
69
102
|
|
|
70
|
-
|
|
71
|
-
if (choice === ALLOW) return;
|
|
72
|
-
return denyResult(reason);
|
|
103
|
+
return promptOrBlock(ctx, reason, `Path: ${filePath}`, () => allowedPaths.add(resolved));
|
|
73
104
|
}
|
|
74
105
|
});
|
|
75
106
|
};
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { resolve, relative } from "node:path";
|
|
7
7
|
|
|
8
|
+
export const OUTSIDE_CWD_REASON = "Accesses path outside working directory";
|
|
9
|
+
|
|
8
10
|
interface DenylistEntry {
|
|
9
11
|
pattern: RegExp;
|
|
10
12
|
reason: string;
|
|
@@ -75,8 +77,20 @@ export function classifyFilePath(filePath: string, projectRoot: string): string
|
|
|
75
77
|
const rel = relative(projectRoot, resolved);
|
|
76
78
|
|
|
77
79
|
if (rel.startsWith("..")) {
|
|
78
|
-
return
|
|
80
|
+
return OUTSIDE_CWD_REASON;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
return findMatchingReason(SENSITIVE_FILE_PATTERNS, filePath);
|
|
82
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns a reason string if the file path resolves outside the given cwd,
|
|
88
|
+
* or null if inside (or empty).
|
|
89
|
+
*/
|
|
90
|
+
export function isOutsideCwd(filePath: string, cwd: string): string | null {
|
|
91
|
+
if (!filePath) return null;
|
|
92
|
+
const resolved = resolve(cwd, filePath);
|
|
93
|
+
const rel = relative(cwd, resolved);
|
|
94
|
+
if (rel.startsWith("..")) return OUTSIDE_CWD_REASON;
|
|
95
|
+
return null;
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl-regenesislabs/opendcl",
|
|
3
|
-
"version": "0.1.4-
|
|
3
|
+
"version": "0.1.4-22626562583.commit-09a1d03",
|
|
4
4
|
"description": "AI coding assistant for Decentraland SDK7 scene development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"prompts/",
|
|
67
67
|
"context/"
|
|
68
68
|
],
|
|
69
|
-
"commit": "
|
|
69
|
+
"commit": "09a1d037c3a42a9041ce7baccd6d22411cb365ed"
|
|
70
70
|
}
|