@adiholick/nvstudio-mcp 2.2.0 → 2.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 +9 -3
- package/dist/index.js +17 -0
- package/dist/roblox-bridge.js +25 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,8 +32,8 @@ curl -fsSL https://raw.githubusercontent.com/Adiholick/nvstudio-mcp/main/install
|
|
|
32
32
|
**Apa saja yang dilakukan installer ini secara otomatis?**
|
|
33
33
|
1. 📦 Mengunduh source code, memasang dependensi Node.js, dan mengkompilasi TypeScript (*Bridge Server*).
|
|
34
34
|
2. 🧩 **Memasang Plugin Roblox Studio (`nvstudio_mcp.rbxmx`) otomatis** ke folder sistem Roblox Studio Anda (`%LOCALAPPDATA%\Roblox\Plugins` di Windows atau `~/Documents/ROBLOX/Plugins` di macOS).
|
|
35
|
-
3.
|
|
36
|
-
4. ⚙️ Melakukan auto-konfigurasi jika mendeteksi editor **Cursor** (`.cursor/mcp.json`).
|
|
35
|
+
3. 🧠 **Universal AI Skill Installer**: Secara cerdas memindai dan mengunduh library skill 29+ *roblox-brain* dan *nvstudio-mcp-guide*, lalu menginjeksinya langsung ke dalam struktur `skills/` dari **AI Agent apapun** yang Anda gunakan (mendukung **Antigravity IDE**, **Cursor**, **Claude Code**, **Codex**, **OpenCode**, dan **Roo Code**).
|
|
36
|
+
4. ⚙️ Melakukan auto-konfigurasi jika mendeteksi editor **Cursor** (`.cursor/mcp.json`) atau **Antigravity** (`mcp_config.json`).
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
@@ -126,9 +126,15 @@ Installer `install.sh` sebelumnya mengkloning repositori dan menginstal Node.js
|
|
|
126
126
|
rm -rf ~/.nvstudio-mcp
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
### 4. Hapus Konfigurasi dari Editor AI Anda
|
|
129
|
+
### 4. Hapus Konfigurasi dan Skills dari Editor AI Anda
|
|
130
130
|
Jika Anda memasukkan konfigurasi MCP secara otomatis ke Cursor atau secara manual ke Claude Desktop, buka file pengaturan `mcp.json` tersebut dan **hapus blok `"nvstudio-mcp"`** dari dalam objek `mcpServers`.
|
|
131
131
|
|
|
132
|
+
**Untuk membersihkan skill bawaan (Universal Skill Installer):**
|
|
133
|
+
Anda bisa menghapus manual symlink/folder shortcut (yang bernama awalan `roblox-`) dari dalam folder konfigurasi agen Anda:
|
|
134
|
+
- **Cursor / Workspace Lokal**: Hapus isi `.cursor/skills` dan `.cursor/roblox-brain.md`
|
|
135
|
+
- **Claude Code**: Hapus dari `~/.claude/skills`
|
|
136
|
+
- **Codex / OpenCode**: Hapus dari direktori lokal atau global (`~/.codex/skills`, `~/.opencode/skills`).
|
|
137
|
+
|
|
132
138
|
---
|
|
133
139
|
|
|
134
140
|
**Selamat Menciptakan Game Impian Anda dengan AI! 🎮🤖**
|
package/dist/index.js
CHANGED
|
@@ -140,6 +140,23 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
140
140
|
let result;
|
|
141
141
|
if (roblox_bridge_1.isBridgeHosting) {
|
|
142
142
|
// Instance ini sendiri yang meng-host bridge server
|
|
143
|
+
if (!(0, roblox_bridge_1.isStudioConnected)()) {
|
|
144
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
145
|
+
if (!(0, roblox_bridge_1.isStudioConnected)()) {
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: "text",
|
|
150
|
+
text: JSON.stringify({
|
|
151
|
+
status: "error",
|
|
152
|
+
error: "Roblox Studio tidak terdeteksi aktif. Pastikan Roblox Studio dibuka, place telah dimuat, dan plugin nvstudio-mcp dalam status terhubung.",
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
isError: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
143
160
|
result = await (0, task_queue_1.addTaskToQueue)(command, target, data);
|
|
144
161
|
}
|
|
145
162
|
else {
|
package/dist/roblox-bridge.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.isBridgeHosting = void 0;
|
|
7
|
+
exports.isStudioConnected = isStudioConnected;
|
|
7
8
|
exports.setMcpConnected = setMcpConnected;
|
|
8
9
|
exports.startBridgeServer = startBridgeServer;
|
|
9
10
|
const express_1 = __importDefault(require("express"));
|
|
@@ -31,13 +32,21 @@ const studioEventQueues = new Map();
|
|
|
31
32
|
const studioLastSeen = new Map();
|
|
32
33
|
setInterval(() => {
|
|
33
34
|
const now = Date.now();
|
|
35
|
+
let changed = false;
|
|
34
36
|
for (const [sid, lastSeen] of studioLastSeen.entries()) {
|
|
35
|
-
if (now - lastSeen >
|
|
37
|
+
if (now - lastSeen > 6000) {
|
|
36
38
|
studioEventQueues.delete(sid);
|
|
37
39
|
studioLastSeen.delete(sid);
|
|
40
|
+
changed = true;
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
|
-
|
|
43
|
+
if (changed) {
|
|
44
|
+
broadcastStatus();
|
|
45
|
+
}
|
|
46
|
+
}, 3000);
|
|
47
|
+
function isStudioConnected() {
|
|
48
|
+
return studioEventQueues.size > 0;
|
|
49
|
+
}
|
|
41
50
|
function enqueueForStudio(studioId, event) {
|
|
42
51
|
if (studioId) {
|
|
43
52
|
// Event untuk studio tertentu
|
|
@@ -92,7 +101,7 @@ function sendEvent(peer, kind, payload) {
|
|
|
92
101
|
function broadcastStatus() {
|
|
93
102
|
const statusEvent = {
|
|
94
103
|
mcpConnected,
|
|
95
|
-
studioCount:
|
|
104
|
+
studioCount: studioEventQueues.size,
|
|
96
105
|
serverVersion: SERVER_VERSION,
|
|
97
106
|
};
|
|
98
107
|
broadcastEvent('status', statusEvent);
|
|
@@ -179,12 +188,12 @@ function startBridgeServer(port, isDaemon = false) {
|
|
|
179
188
|
io.on('connection', (socket) => {
|
|
180
189
|
socket.emit('init', {
|
|
181
190
|
logs: activityLogs,
|
|
182
|
-
stats: { totalTasks, successCount, errorCount, sessionStart, studioConnected:
|
|
191
|
+
stats: { totalTasks, successCount, errorCount, sessionStart, studioConnected: studioEventQueues.size > 0, port },
|
|
183
192
|
});
|
|
184
193
|
});
|
|
185
194
|
// ── /api/stats ─────────────────────────────────────────────────────────────
|
|
186
195
|
app.get('/api/stats', (req, res) => {
|
|
187
|
-
const activeStudios =
|
|
196
|
+
const activeStudios = studioEventQueues.size;
|
|
188
197
|
res.json({
|
|
189
198
|
totalTasks, successCount, errorCount, sessionStart,
|
|
190
199
|
studioConnected: activeStudios > 0,
|
|
@@ -196,7 +205,7 @@ function startBridgeServer(port, isDaemon = false) {
|
|
|
196
205
|
// ── /api/ping ─────────────────────────────────────────────────────────────
|
|
197
206
|
app.get('/api/ping', (req, res) => {
|
|
198
207
|
const uptime = Math.floor((Date.now() - new Date(sessionStart).getTime()) / 1000);
|
|
199
|
-
const activeStudios =
|
|
208
|
+
const activeStudios = studioEventQueues.size;
|
|
200
209
|
res.json({
|
|
201
210
|
status: 'ok',
|
|
202
211
|
version: SERVER_VERSION,
|
|
@@ -329,6 +338,16 @@ function startBridgeServer(port, isDaemon = false) {
|
|
|
329
338
|
// ── /api/tasks/enqueue (dari proses MCP eksternal / bridge forwarding) ────
|
|
330
339
|
app.post('/api/tasks/enqueue', async (req, res) => {
|
|
331
340
|
const { command, target, data } = req.body;
|
|
341
|
+
// Fast-check: pastikan setidaknya 1 Studio aktif polling
|
|
342
|
+
if (studioEventQueues.size === 0) {
|
|
343
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
344
|
+
if (studioEventQueues.size === 0) {
|
|
345
|
+
return res.json({
|
|
346
|
+
status: 'error',
|
|
347
|
+
error: 'Roblox Studio tidak terdeteksi aktif. Pastikan Roblox Studio dibuka, place telah dimuat, dan plugin nvstudio-mcp dalam status terhubung.'
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
332
351
|
try {
|
|
333
352
|
const result = await (0, task_queue_1.addTaskToQueue)(command, target, data);
|
|
334
353
|
res.json({ status: 'success', result });
|