@dcl-regenesislabs/opendcl 0.2.1-26502482653.commit-5089b10 → 0.2.1
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 +3 -5
- package/context/sdk7-cheat-sheet.md +0 -4
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/extensions/dcl-init.ts +6 -58
- package/extensions/dcl-setup-ollama.ts +312 -0
- package/package.json +4 -3
- package/prompts/system.md +41 -71
- package/skills/add-3d-models/SKILL.md +70 -120
- package/skills/add-interactivity/SKILL.md +2 -74
- package/skills/advanced-input/SKILL.md +1 -34
- package/skills/advanced-rendering/SKILL.md +9 -82
- package/skills/animations-tweens/SKILL.md +98 -203
- package/skills/audio-video/SKILL.md +83 -184
- package/skills/build-ui/SKILL.md +2 -25
- package/skills/camera-control/SKILL.md +7 -78
- package/skills/create-scene/SKILL.md +13 -56
- package/skills/deploy-scene/SKILL.md +0 -12
- package/skills/deploy-worlds/SKILL.md +0 -35
- package/skills/game-design/SKILL.md +2 -1
- package/skills/lighting-environment/SKILL.md +56 -103
- package/skills/multiplayer-sync/SKILL.md +2 -31
- package/skills/nft-blockchain/SKILL.md +40 -45
- package/skills/optimize-scene/SKILL.md +2 -7
- package/skills/player-avatar/SKILL.md +7 -133
- package/skills/scene-runtime/SKILL.md +5 -9
- package/skills/visual-feedback/SKILL.md +0 -1
- package/skills/audio-analysis/SKILL.md +0 -164
- package/skills/editor-gizmo/.gitignore +0 -11
- package/skills/editor-gizmo/SKILL.md +0 -222
- package/skills/editor-gizmo/src/__editor/camera.ts +0 -277
- package/skills/editor-gizmo/src/__editor/discovery.ts +0 -210
- package/skills/editor-gizmo/src/__editor/drag.ts +0 -265
- package/skills/editor-gizmo/src/__editor/gizmo.ts +0 -496
- package/skills/editor-gizmo/src/__editor/history.ts +0 -72
- package/skills/editor-gizmo/src/__editor/index.ts +0 -138
- package/skills/editor-gizmo/src/__editor/input.ts +0 -55
- package/skills/editor-gizmo/src/__editor/math-utils.ts +0 -114
- package/skills/editor-gizmo/src/__editor/persistence.ts +0 -113
- package/skills/editor-gizmo/src/__editor/selection.ts +0 -157
- package/skills/editor-gizmo/src/__editor/state.ts +0 -117
- package/skills/editor-gizmo/src/__editor/ui.tsx +0 -699
- package/skills/npcs/SKILL.md +0 -180
- package/skills/particle-system/SKILL.md +0 -222
- package/skills/player-physics/SKILL.md +0 -93
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ The result: **more creators building more scenes, faster.**
|
|
|
26
26
|
## Features
|
|
27
27
|
|
|
28
28
|
- **Branded header** — on startup, displays a block-character "Decentraland" ASCII art banner with version and working directory. Falls back to a compact text header on narrow terminals
|
|
29
|
-
- **Multi-provider LLM support** — works with Claude, OpenAI, Google, OpenRouter, and more
|
|
29
|
+
- **Multi-provider LLM support** — works with Claude, OpenAI, Google, Ollama (free/local), OpenRouter, and more
|
|
30
30
|
- **Scene-aware** — automatically detects your project's `scene.json`, SDK version, and entry points
|
|
31
31
|
- **20 built-in skills** — scaffolding, 3D models, interactivity, UI, animations, multiplayer, authoritative server, audio/video, deployment (Genesis City & Worlds), optimization, camera control, lighting, player/avatar, NFT/blockchain, advanced rendering, advanced input, scene runtime, visual feedback, game design
|
|
32
32
|
- **Integrated commands** — `/init` to scaffold, `/preview` to launch the dev server, `/tasks` to manage running processes, `/review` to audit code
|
|
@@ -99,7 +99,6 @@ This uses the open [skills](https://github.com/vercel-labs/skills) CLI to copy S
|
|
|
99
99
|
| `/deploy` | Deploy the scene to Genesis City or a World (auto-detects from scene.json) |
|
|
100
100
|
| `/tasks` | Interactively manage running background processes (preview server, etc.) |
|
|
101
101
|
| `/review` | Review scene code for quality, performance, and SDK7 best practices |
|
|
102
|
-
| `/save-editor` | Apply pending visual editor changes to scene source code |
|
|
103
102
|
| `/explain <concept>` | Explain a Decentraland SDK7 concept (e.g., `/explain tweens`) |
|
|
104
103
|
|
|
105
104
|
The agent also has a `screenshot` tool it can call automatically to see the running preview. On first use it asks for your permission to open a headless browser. The browser stays open for the entire session — no repeated logins.
|
|
@@ -130,7 +129,6 @@ OpenDCL loads domain-specific skills on demand based on what you're asking:
|
|
|
130
129
|
| `scene-runtime` | Async tasks, fetch, timers, realm info, restricted actions, testing |
|
|
131
130
|
| `visual-feedback` | Use the screenshot tool to see your scene, verify changes, iterate visually |
|
|
132
131
|
| `game-design` | Plan game architecture, scene limits, state management, MVP planning |
|
|
133
|
-
| `editor-gizmo` | Use a visual in-scene editor with translate/rotate gizmos |
|
|
134
132
|
|
|
135
133
|
## How It Works
|
|
136
134
|
|
|
@@ -152,7 +150,7 @@ opendcl/
|
|
|
152
150
|
│ └── scene-context.ts # Scene detection & context formatting
|
|
153
151
|
├── extensions/
|
|
154
152
|
│ ├── dcl-context.ts # Auto-detect scene, inject metadata
|
|
155
|
-
│ ├── dcl-init.ts # /init command
|
|
153
|
+
│ ├── dcl-init.ts # /init command
|
|
156
154
|
│ ├── dcl-preview.ts # /preview command
|
|
157
155
|
│ ├── dcl-deploy.ts # /deploy command
|
|
158
156
|
│ ├── dcl-setup.ts # /setup command (cloud API provider config)
|
|
@@ -161,7 +159,6 @@ opendcl/
|
|
|
161
159
|
│ ├── dcl-validate.ts # Post-write TypeScript validation
|
|
162
160
|
│ ├── dcl-screenshot.ts # screenshot tool (headless Chrome, persistent browser)
|
|
163
161
|
│ ├── dcl-tasks.ts # /tasks command (process manager)
|
|
164
|
-
│ ├── dcl-editor-save.ts # /save-editor command (apply visual editor changes)
|
|
165
162
|
│ ├── process-registry.ts # Shared background process registry
|
|
166
163
|
│ └── permissions/ # Permission gate for dangerous operations
|
|
167
164
|
├── skills/ # 20 SKILL.md files (domain expertise)
|
|
@@ -234,6 +231,7 @@ OpenDCL supports any provider compatible with pi-coding-agent:
|
|
|
234
231
|
| Anthropic (Claude) | `ANTHROPIC_API_KEY` | Best quality |
|
|
235
232
|
| OpenAI | `OPENAI_API_KEY` | GPT-4o, o1, etc. |
|
|
236
233
|
| Google | `GOOGLE_API_KEY` | Gemini models |
|
|
234
|
+
| Ollama | — | Free, runs locally |
|
|
237
235
|
| OpenRouter | `OPENROUTER_API_KEY` | Access to many models |
|
|
238
236
|
|
|
239
237
|
Set the environment variable or enter the key on first run. Switch models anytime with `Ctrl+P`.
|
|
@@ -34,10 +34,6 @@ removeEntityWithChildren(engine, entity)
|
|
|
34
34
|
|
|
35
35
|
// Components — CRUD
|
|
36
36
|
Transform.create(entity, { position: Vector3.create(8, 1, 8) })
|
|
37
|
-
// ⚠️ NEVER pass undefined values in Transform fields — the SDK serializer crashes
|
|
38
|
-
// reading .x on undefined. If a field is optional, omit the key entirely:
|
|
39
|
-
// BAD: Transform.create(e, { position, rotation }) // rotation may be undefined
|
|
40
|
-
// GOOD: Transform.create(e, rotation ? { position, rotation } : { position })
|
|
41
37
|
const t = Transform.get(entity) // read-only, throws if missing
|
|
42
38
|
const t = Transform.getMutable(entity) // mutable reference
|
|
43
39
|
const t = Transform.getOrNull(entity) // read-only, returns null if missing
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,10 @@ const extensions = headless
|
|
|
67
67
|
"dcl-asset-path.ts",
|
|
68
68
|
"dcl-screenshot.ts",
|
|
69
69
|
];
|
|
70
|
+
// Conditionally load dcl-setup-ollama (hidden by default, enable with ENABLE_OLLAMA_SETUP=true)
|
|
71
|
+
if (!headless && process.env.ENABLE_OLLAMA_SETUP === "true") {
|
|
72
|
+
extensions.push("dcl-setup-ollama.ts");
|
|
73
|
+
}
|
|
70
74
|
for (const ext of extensions) {
|
|
71
75
|
args.push("-e", join(extDir, ext));
|
|
72
76
|
}
|
|
@@ -86,6 +90,14 @@ if (!isDev()) {
|
|
|
86
90
|
}
|
|
87
91
|
// InteractiveMode patches — only needed for terminal UI, skip in headless mode
|
|
88
92
|
if (!headless) {
|
|
93
|
+
// Suppress pi's generic "No models available" warning — our dcl-setup-ollama
|
|
94
|
+
// extension shows a more helpful message that mentions /setup-ollama.
|
|
95
|
+
const _showWarning = InteractiveMode.prototype.showWarning;
|
|
96
|
+
InteractiveMode.prototype.showWarning = function (msg) {
|
|
97
|
+
if (msg.startsWith("No models available"))
|
|
98
|
+
return;
|
|
99
|
+
_showWarning.call(this, msg);
|
|
100
|
+
};
|
|
89
101
|
// Suppress pi's "What's New" changelog notification on startup — it shows pi's
|
|
90
102
|
// own version/changes, which confuses OpenDCL users.
|
|
91
103
|
InteractiveMode.prototype.getChangelogForDisplay = function () {
|
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,8EAA8E;AAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC7C,IAAI,QAAQ,EAAE,CAAC;IACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,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,kBAAkB;AAClB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/extensions/dcl-init.ts
CHANGED
|
@@ -3,40 +3,24 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers the `init` tool (LLM-callable) and `/init` command that scaffolds
|
|
5
5
|
* a new Decentraland scene project using `npx @dcl/sdk-commands init`.
|
|
6
|
-
* After scaffolding, triggers the editor-gizmo skill to set up the visual editor.
|
|
7
|
-
* On session start, prompts the user to enable the editor if a scene exists but lacks it.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
|
|
11
9
|
import { Type } from "@sinclair/typebox";
|
|
12
10
|
import { join } from "node:path";
|
|
13
11
|
import { readFile, writeFile } from "node:fs/promises";
|
|
14
|
-
import { fileExists
|
|
15
|
-
|
|
16
|
-
function triggerEditorSkill(pi: { sendMessage(msg: unknown, opts?: unknown): void }) {
|
|
17
|
-
pi.sendMessage(
|
|
18
|
-
{
|
|
19
|
-
customType: "editor-setup",
|
|
20
|
-
content: "Scene initialized (dependencies not yet installed). Now set up the visual editor by following the editor-gizmo skill.",
|
|
21
|
-
display: true,
|
|
22
|
-
},
|
|
23
|
-
{ triggerTurn: true }
|
|
24
|
-
);
|
|
25
|
-
}
|
|
12
|
+
import { fileExists } from "./scene-utils.js";
|
|
26
13
|
|
|
27
14
|
async function initScene(
|
|
28
15
|
cwd: string,
|
|
29
|
-
pi: {
|
|
30
|
-
exec(cmd: string, args: string[], opts?: unknown): Promise<{ code: number; stdout: string; stderr: string }>;
|
|
31
|
-
sendMessage(msg: unknown, opts?: unknown): void;
|
|
32
|
-
}
|
|
16
|
+
pi: { exec(cmd: string, args: string[], opts?: unknown): Promise<{ code: number; stdout: string; stderr: string }> }
|
|
33
17
|
): Promise<{ message: string; isError?: boolean }> {
|
|
34
18
|
if (await fileExists(join(cwd, "scene.json"))) {
|
|
35
19
|
return { message: "A scene.json already exists in this directory. Aborting to prevent overwriting.", isError: true };
|
|
36
20
|
}
|
|
37
21
|
|
|
38
22
|
try {
|
|
39
|
-
const result = await pi.exec("npx", ["@dcl/sdk-commands", "init", "--yes"
|
|
23
|
+
const result = await pi.exec("npx", ["@dcl/sdk-commands", "init", "--yes"], {
|
|
40
24
|
cwd,
|
|
41
25
|
timeout: 180000,
|
|
42
26
|
});
|
|
@@ -52,23 +36,7 @@ async function initScene(
|
|
|
52
36
|
} catch {
|
|
53
37
|
// Non-fatal: scene was still initialized successfully
|
|
54
38
|
}
|
|
55
|
-
|
|
56
|
-
// Append OpenDCL build artifacts to .gitignore so they don't get committed.
|
|
57
|
-
// main.crdt is generated from main-entities.ts at bundle time.
|
|
58
|
-
try {
|
|
59
|
-
const ignorePath = join(cwd, ".gitignore");
|
|
60
|
-
let existing = "";
|
|
61
|
-
try { existing = await readFile(ignorePath, "utf-8"); } catch {}
|
|
62
|
-
if (!existing.split(/\r?\n/).includes("main.crdt")) {
|
|
63
|
-
const sep = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
64
|
-
await writeFile(ignorePath, existing + sep + "main.crdt\n");
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// Non-fatal: scene still works without .gitignore updates
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
triggerEditorSkill(pi);
|
|
71
|
-
return { message: "Scene initialized! Setting up visual editor..." };
|
|
39
|
+
return { message: "Scene initialized and dependencies installed! Use the preview tool to start." };
|
|
72
40
|
} else {
|
|
73
41
|
return { message: `Init failed (exit code ${result.code}): ${result.stderr || result.stdout}`, isError: true };
|
|
74
42
|
}
|
|
@@ -82,7 +50,7 @@ const extension: ExtensionFactory = (pi) => {
|
|
|
82
50
|
name: "init",
|
|
83
51
|
label: "Init Scene",
|
|
84
52
|
description:
|
|
85
|
-
"Initialize a new Decentraland SDK7 scene
|
|
53
|
+
"Initialize a new Decentraland SDK7 scene. Scaffolds scene.json, package.json, tsconfig.json, and src/index.ts. Use when user wants to create or start a new scene.",
|
|
86
54
|
parameters: Type.Object({}),
|
|
87
55
|
async execute(_id, _params, _signal, _onUpdate, ctx) {
|
|
88
56
|
const result = await initScene(ctx.cwd, pi);
|
|
@@ -92,7 +60,7 @@ const extension: ExtensionFactory = (pi) => {
|
|
|
92
60
|
});
|
|
93
61
|
|
|
94
62
|
pi.registerCommand("init", {
|
|
95
|
-
description: "Initialize a new Decentraland scene project
|
|
63
|
+
description: "Initialize a new Decentraland scene project in the current directory",
|
|
96
64
|
handler: async (_args, ctx) => {
|
|
97
65
|
ctx.ui.notify("Initializing new Decentraland scene...", "info");
|
|
98
66
|
const result = await initScene(ctx.cwd, pi);
|
|
@@ -100,26 +68,6 @@ const extension: ExtensionFactory = (pi) => {
|
|
|
100
68
|
if (!result.isError) await ctx.reload();
|
|
101
69
|
},
|
|
102
70
|
});
|
|
103
|
-
|
|
104
|
-
// Prompt on session start if scene exists but editor is not installed
|
|
105
|
-
let editorPromptShown = false;
|
|
106
|
-
pi.on("before_agent_start", async (_event, ctx) => {
|
|
107
|
-
if (editorPromptShown) return;
|
|
108
|
-
editorPromptShown = true;
|
|
109
|
-
|
|
110
|
-
const sceneRoot = await findSceneRoot(ctx.cwd);
|
|
111
|
-
if (!sceneRoot) return;
|
|
112
|
-
|
|
113
|
-
if (await fileExists(join(sceneRoot, "src", "__editor", "state.ts"))) return;
|
|
114
|
-
|
|
115
|
-
const enable = await ctx.ui.confirm(
|
|
116
|
-
"Visual Editor",
|
|
117
|
-
"Enable the visual editor for this scene?"
|
|
118
|
-
);
|
|
119
|
-
if (!enable) return;
|
|
120
|
-
|
|
121
|
-
triggerEditorSkill(pi);
|
|
122
|
-
});
|
|
123
71
|
};
|
|
124
72
|
|
|
125
73
|
export default extension;
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DCL Setup Ollama Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers the /setup-ollama command that walks users through
|
|
5
|
+
* model selection and configuration for a free local LLM setup.
|
|
6
|
+
* On session start, nudges users who have no provider configured.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
|
|
15
|
+
interface OllamaProvider {
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
api?: string;
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
models?: { id: string }[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const API_KEY_ENV_VARS = [
|
|
23
|
+
"ANTHROPIC_API_KEY",
|
|
24
|
+
"OPENAI_API_KEY",
|
|
25
|
+
"GOOGLE_API_KEY",
|
|
26
|
+
"OPENROUTER_API_KEY",
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export const OLLAMA_MODELS = [
|
|
30
|
+
{ id: "qwen2.5-coder:32b", label: "qwen2.5-coder:32b (Recommended — best coding benchmarks, ~18GB)" },
|
|
31
|
+
{ id: "qwen3-coder:30b", label: "qwen3-coder:30b (Latest Alibaba coder, 256K context, ~19GB)" },
|
|
32
|
+
{ id: "devstral:24b", label: "devstral:24b (Mistral coding agent model, ~14GB)" },
|
|
33
|
+
{ id: "glm-4.7-flash", label: "glm-4.7-flash (Reasoning + code generation, ~25GB)" },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
async function readJsonFile<T>(path: string, fallback: T): Promise<T> {
|
|
37
|
+
try {
|
|
38
|
+
const content = await readFile(path, "utf-8");
|
|
39
|
+
return JSON.parse(content);
|
|
40
|
+
} catch {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function writeJsonFile(path: string, data: unknown): Promise<void> {
|
|
46
|
+
await mkdir(dirname(path), { recursive: true });
|
|
47
|
+
await writeFile(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function writeModelsConfig(modelsPath: string, modelId: string): Promise<void> {
|
|
51
|
+
const config = await readJsonFile<{ providers?: Record<string, unknown> }>(modelsPath, {});
|
|
52
|
+
config.providers ??= {};
|
|
53
|
+
|
|
54
|
+
const ollama = config.providers.ollama as OllamaProvider | undefined;
|
|
55
|
+
if (ollama) {
|
|
56
|
+
ollama.models ??= [];
|
|
57
|
+
if (!ollama.models.some((m) => m.id === modelId)) {
|
|
58
|
+
ollama.models.push({ id: modelId });
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
config.providers.ollama = {
|
|
62
|
+
baseUrl: "http://localhost:11434/v1",
|
|
63
|
+
api: "openai-completions",
|
|
64
|
+
apiKey: "ollama",
|
|
65
|
+
models: [{ id: modelId }],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await writeJsonFile(modelsPath, config);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function setDefaultModel(settingsPath: string, provider: string, modelId: string): Promise<void> {
|
|
73
|
+
const settings = await readJsonFile<Record<string, unknown>>(settingsPath, {});
|
|
74
|
+
|
|
75
|
+
settings.defaultProvider = provider;
|
|
76
|
+
settings.defaultModel = modelId;
|
|
77
|
+
|
|
78
|
+
await writeJsonFile(settingsPath, settings);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function isProviderConfigured(): Promise<boolean> {
|
|
82
|
+
if (API_KEY_ENV_VARS.some((v) => process.env[v])) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const configDir = join(homedir(), ".opendcl", "agent");
|
|
87
|
+
|
|
88
|
+
const modelsConfig = await readJsonFile<{ providers?: Record<string, unknown> }>(join(configDir, "models.json"), {});
|
|
89
|
+
if (modelsConfig.providers != null && Object.keys(modelsConfig.providers).length > 0) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const authConfig = await readJsonFile<Record<string, unknown>>(join(configDir, "auth.json"), {});
|
|
94
|
+
return Object.keys(authConfig).length > 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function parseOllamaList(output: string): string[] {
|
|
98
|
+
const lines = output.split(/\r?\n/).filter((l) => l.trim());
|
|
99
|
+
// Skip header line (starts with "NAME")
|
|
100
|
+
const dataLines = lines.filter((l) => !l.startsWith("NAME"));
|
|
101
|
+
return dataLines
|
|
102
|
+
.map((l) => l.split(/\s+/)[0])
|
|
103
|
+
.filter(Boolean)
|
|
104
|
+
.map((name) => name.replace(/:latest$/, ""));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function removeOllamaModel(
|
|
108
|
+
modelsPath: string,
|
|
109
|
+
settingsPath: string,
|
|
110
|
+
modelId: string,
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
const config = await readJsonFile<{ providers?: Record<string, unknown> }>(modelsPath, {});
|
|
113
|
+
const ollama = config.providers?.ollama as OllamaProvider | undefined;
|
|
114
|
+
if (ollama?.models) {
|
|
115
|
+
ollama.models = ollama.models.filter((m) => m.id !== modelId);
|
|
116
|
+
if (ollama.models.length === 0) {
|
|
117
|
+
delete config.providers!.ollama;
|
|
118
|
+
}
|
|
119
|
+
await writeJsonFile(modelsPath, config);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const settings = await readJsonFile<Record<string, unknown>>(settingsPath, {});
|
|
123
|
+
if (settings.defaultProvider === "ollama" && settings.defaultModel === modelId) {
|
|
124
|
+
delete settings.defaultProvider;
|
|
125
|
+
delete settings.defaultModel;
|
|
126
|
+
await writeJsonFile(settingsPath, settings);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Run ollama commands through the user's login shell so the full PATH is used.
|
|
132
|
+
* (pi.exec without shell won't find binaries added by installers to profile files.)
|
|
133
|
+
*/
|
|
134
|
+
function ollamaExec(pi: Parameters<ExtensionFactory>[0], args: string, timeout = 10000) {
|
|
135
|
+
const shell = process.env.SHELL || "/bin/sh";
|
|
136
|
+
return pi.exec(shell, ["-lc", `ollama ${args}`], { timeout }).catch(() => null);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function stripAnsi(text: string): string {
|
|
140
|
+
return text.replace(/\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g, "");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Extract a clean, human-readable progress line from raw ollama pull output.
|
|
145
|
+
* Ollama outputs ANSI-heavy terminal UI — this strips escape codes and
|
|
146
|
+
* picks the most informative line (percentage progress > phase labels).
|
|
147
|
+
*/
|
|
148
|
+
export function extractPullProgress(raw: string): string | null {
|
|
149
|
+
const clean = stripAnsi(raw);
|
|
150
|
+
const lines = clean.split(/\r\n|\r|\n/).map((l) => l.trim()).filter(Boolean);
|
|
151
|
+
// Prefer the line with download percentage (e.g. "pulling abc123: 45% 8 GB/18 GB 12 MB/s")
|
|
152
|
+
const progress = lines.findLast((l) => /\d+%/.test(l));
|
|
153
|
+
if (progress) return progress;
|
|
154
|
+
// Fall back to phase lines like "pulling manifest", "verifying sha256 digest"
|
|
155
|
+
const phase = lines.findLast((l) => /^(pulling|verifying|writing|success)/.test(l));
|
|
156
|
+
return phase ?? null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Pull a model with streaming progress via spawn.
|
|
161
|
+
* Throttles notifications to avoid UI spam (one update every 2 seconds max).
|
|
162
|
+
*/
|
|
163
|
+
export function ollamaPull(
|
|
164
|
+
modelId: string,
|
|
165
|
+
onProgress: (line: string) => void,
|
|
166
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
167
|
+
return new Promise((resolve) => {
|
|
168
|
+
const shell = process.env.SHELL || "/bin/sh";
|
|
169
|
+
const child = spawn(shell, ["-lc", `ollama pull ${modelId}`], {
|
|
170
|
+
stdio: "pipe",
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
let lastNotify = 0;
|
|
174
|
+
let lastLine = "";
|
|
175
|
+
let errorOutput = "";
|
|
176
|
+
|
|
177
|
+
function handleData(data: Buffer): void {
|
|
178
|
+
const text = data.toString();
|
|
179
|
+
errorOutput += text;
|
|
180
|
+
const line = extractPullProgress(text);
|
|
181
|
+
if (!line) return;
|
|
182
|
+
lastLine = line;
|
|
183
|
+
const now = Date.now();
|
|
184
|
+
if (now - lastNotify >= 2000) {
|
|
185
|
+
lastNotify = now;
|
|
186
|
+
onProgress(line);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
child.stdout?.on("data", handleData);
|
|
191
|
+
child.stderr?.on("data", handleData);
|
|
192
|
+
|
|
193
|
+
child.on("error", (err) => {
|
|
194
|
+
resolve({ success: false, error: err.message });
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
child.on("exit", (code) => {
|
|
198
|
+
if (lastLine) onProgress(lastLine);
|
|
199
|
+
if (code === 0) {
|
|
200
|
+
resolve({ success: true });
|
|
201
|
+
} else {
|
|
202
|
+
resolve({ success: false, error: stripAnsi(errorOutput).slice(-500) });
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const extension: ExtensionFactory = (pi) => {
|
|
209
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
210
|
+
if (!(await isProviderConfigured())) {
|
|
211
|
+
ctx.ui.notify(
|
|
212
|
+
"Get started by running /setup to configure a cloud provider",
|
|
213
|
+
"warning",
|
|
214
|
+
);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const configDir = join(homedir(), ".opendcl", "agent");
|
|
219
|
+
const settingsPath = join(configDir, "settings.json");
|
|
220
|
+
const settings = await readJsonFile<Record<string, unknown>>(settingsPath, {});
|
|
221
|
+
if (settings.defaultProvider !== "ollama") return;
|
|
222
|
+
|
|
223
|
+
const defaultModel = settings.defaultModel as string | undefined;
|
|
224
|
+
if (!defaultModel) return;
|
|
225
|
+
|
|
226
|
+
const listResult = await ollamaExec(pi, "list");
|
|
227
|
+
if (!listResult || listResult.code !== 0) return;
|
|
228
|
+
|
|
229
|
+
const installed = parseOllamaList(listResult.stdout || "");
|
|
230
|
+
if (installed.includes(defaultModel)) return;
|
|
231
|
+
|
|
232
|
+
const modelsPath = join(configDir, "models.json");
|
|
233
|
+
await removeOllamaModel(modelsPath, settingsPath, defaultModel);
|
|
234
|
+
ctx.ui.notify(
|
|
235
|
+
`Model '${defaultModel}' is no longer installed in Ollama. Run /setup-ollama to configure a new model.`,
|
|
236
|
+
"warning",
|
|
237
|
+
);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
pi.registerCommand("setup-ollama", {
|
|
241
|
+
description: "Configure Ollama as your free local LLM provider",
|
|
242
|
+
handler: async (_args, ctx) => {
|
|
243
|
+
const configDir = join(homedir(), ".opendcl", "agent");
|
|
244
|
+
|
|
245
|
+
const versionResult = await ollamaExec(pi, "--version");
|
|
246
|
+
if (!versionResult || versionResult.code !== 0) {
|
|
247
|
+
ctx.ui.notify("Ollama is not installed. Download it from https://ollama.com then run /setup-ollama again.", "warning");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const listResult = await ollamaExec(pi, "list");
|
|
252
|
+
if (!listResult || listResult.code !== 0) {
|
|
253
|
+
ctx.ui.notify("Ollama is installed but not running. Start it with 'ollama serve', then run /setup-ollama again.", "warning");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const installed = parseOllamaList(listResult.stdout || "");
|
|
258
|
+
const theme = ctx.ui.theme;
|
|
259
|
+
const sorted = [...OLLAMA_MODELS].sort((a, b) => {
|
|
260
|
+
const aInstalled = installed.includes(a.id) ? 0 : 1;
|
|
261
|
+
const bInstalled = installed.includes(b.id) ? 0 : 1;
|
|
262
|
+
return aInstalled - bInstalled;
|
|
263
|
+
});
|
|
264
|
+
const labels = sorted.map((m) =>
|
|
265
|
+
installed.includes(m.id)
|
|
266
|
+
? `${m.label} ${theme.fg("success", "● ready")}`
|
|
267
|
+
: `${m.label} ${theme.fg("dim", "○ needs download")}`,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const selected = await ctx.ui.select("Which model do you want to use?", labels);
|
|
271
|
+
if (!selected) {
|
|
272
|
+
ctx.ui.notify("Setup cancelled.", "info");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const model = sorted.find((m) => selected.startsWith(m.label));
|
|
277
|
+
if (!model) {
|
|
278
|
+
ctx.ui.notify("Invalid selection.", "error");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const alreadyInstalled = installed.includes(model.id);
|
|
283
|
+
if (!alreadyInstalled) {
|
|
284
|
+
ctx.ui.setStatus("pull", `Pulling ${model.id}...`);
|
|
285
|
+
const pullResult = await ollamaPull(model.id, (line) => {
|
|
286
|
+
ctx.ui.setStatus("pull", line);
|
|
287
|
+
});
|
|
288
|
+
ctx.ui.setStatus("pull", undefined);
|
|
289
|
+
if (!pullResult.success) {
|
|
290
|
+
ctx.ui.notify(`Failed to pull model: ${pullResult.error || "unknown error"}`, "error");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
ctx.ui.notify("Model ready.", "info");
|
|
295
|
+
|
|
296
|
+
const modelsPath = join(configDir, "models.json");
|
|
297
|
+
await writeModelsConfig(modelsPath, model.id);
|
|
298
|
+
|
|
299
|
+
const settingsPath = join(configDir, "settings.json");
|
|
300
|
+
await setDefaultModel(settingsPath, "ollama", model.id);
|
|
301
|
+
|
|
302
|
+
ctx.ui.notify(
|
|
303
|
+
`Ollama configured: ${model.id}. Reloading...`,
|
|
304
|
+
"info",
|
|
305
|
+
);
|
|
306
|
+
await ctx.reload();
|
|
307
|
+
return;
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export default extension;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl-regenesislabs/opendcl",
|
|
3
|
-
"version": "0.2.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "AI coding assistant for Decentraland SDK7 scene development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"url": "git+https://github.com/dcl-regenesislabs/opendcl.git"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
51
|
+
"@mariozechner/pi-coding-agent": "^0.73.1",
|
|
52
|
+
"@sinclair/typebox": "0.34.48",
|
|
52
53
|
"playwright-core": "^1.58.2"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
@@ -71,5 +72,5 @@
|
|
|
71
72
|
"prompts/",
|
|
72
73
|
"context/"
|
|
73
74
|
],
|
|
74
|
-
"commit": "
|
|
75
|
+
"commit": "96d9b973a1059d26e9b7b972add8b62f4ea08dd3"
|
|
75
76
|
}
|