@adiholick/nvstudio-mcp 2.4.0 → 2.4.2
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/agent-plugin/rules/AGENTS.md +25 -0
- package/agent-plugin/skills/nvstudio-animation-vfx/SKILL.md +98 -1
- package/data/vfx-database.json +266475 -0
- package/dist/build-plugin.js +6 -1
- package/dist/vfx-database.js +7 -2
- package/package.json +3 -2
- package/public/index.html +3 -3
- package/studio-plugin/Main.server.lua +10 -4
- package/studio-plugin/nvstudio_mcp.rbxmx +18 -6
- package/studio-plugin/ui_manager.lua +8 -2
package/dist/build-plugin.js
CHANGED
|
@@ -153,7 +153,12 @@ function syncRuntimeAndPlugins() {
|
|
|
153
153
|
if (fs_1.default.existsSync(publicSrc)) {
|
|
154
154
|
fs_1.default.cpSync(publicSrc, publicDest, { recursive: true, force: true });
|
|
155
155
|
}
|
|
156
|
-
|
|
156
|
+
const dataSrc = path_1.default.join(rootDir, 'data');
|
|
157
|
+
const dataDest = path_1.default.join(nvRuntimeDir, 'data');
|
|
158
|
+
if (fs_1.default.existsSync(dataSrc)) {
|
|
159
|
+
fs_1.default.cpSync(dataSrc, dataDest, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
console.log(`[Build] ✅ Berhasil menyinkronkan runtime ${nvRuntimeDir} (dist, public, studio-plugin, src, data)`);
|
|
157
162
|
}
|
|
158
163
|
catch (err) {
|
|
159
164
|
console.warn(`[Build] Gagal menyinkronkan ke ~/.nvstudio-mcp: ${err.message}`);
|
package/dist/vfx-database.js
CHANGED
|
@@ -11,6 +11,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
11
11
|
const uuid_1 = require("uuid");
|
|
12
12
|
const DATA_DIR = path_1.default.join(process.cwd(), 'data');
|
|
13
13
|
const DB_FILE = path_1.default.join(DATA_DIR, 'vfx-database.json');
|
|
14
|
+
const BUNDLED_DB_FILE = path_1.default.join(__dirname, '..', 'data', 'vfx-database.json');
|
|
14
15
|
// ── Default Seed Presets ───────────────────────────────────────────────────────
|
|
15
16
|
const DEFAULT_PRESETS = [
|
|
16
17
|
{
|
|
@@ -408,9 +409,13 @@ class VfxDatabase {
|
|
|
408
409
|
}
|
|
409
410
|
}
|
|
410
411
|
loadDatabase() {
|
|
411
|
-
|
|
412
|
+
let targetFile = DB_FILE;
|
|
413
|
+
if (!fs_1.default.existsSync(targetFile) && fs_1.default.existsSync(BUNDLED_DB_FILE)) {
|
|
414
|
+
targetFile = BUNDLED_DB_FILE;
|
|
415
|
+
}
|
|
416
|
+
if (fs_1.default.existsSync(targetFile)) {
|
|
412
417
|
try {
|
|
413
|
-
const raw = fs_1.default.readFileSync(
|
|
418
|
+
const raw = fs_1.default.readFileSync(targetFile, 'utf-8');
|
|
414
419
|
const list = JSON.parse(raw);
|
|
415
420
|
for (const item of list) {
|
|
416
421
|
item.category = normalizeVfxCategory(item.category);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adiholick/nvstudio-mcp",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Local Bridge Server MCP for Roblox Studio with Animation, VFX, and Rigging Engines",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"dist",
|
|
11
11
|
"public",
|
|
12
12
|
"studio-plugin",
|
|
13
|
-
"agent-plugin"
|
|
13
|
+
"agent-plugin",
|
|
14
|
+
"data"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
17
|
"build": "tsc && npm run build:plugin",
|
package/public/index.html
CHANGED
|
@@ -1156,7 +1156,7 @@
|
|
|
1156
1156
|
</nav>
|
|
1157
1157
|
|
|
1158
1158
|
<div class="sidebar-footer">
|
|
1159
|
-
<span class="badge-v2" id="pkg-version">v2.4.
|
|
1159
|
+
<span class="badge-v2" id="pkg-version">v2.4.2</span>
|
|
1160
1160
|
<span style="font-size:10px; opacity:0.6;">Model Context Protocol</span>
|
|
1161
1161
|
</div>
|
|
1162
1162
|
</aside>
|
|
@@ -1484,7 +1484,7 @@
|
|
|
1484
1484
|
<div class="page" id="page-about">
|
|
1485
1485
|
<div class="about-section">
|
|
1486
1486
|
<div class="about-hero">
|
|
1487
|
-
<h2>nvstudio-mcp <span class="v2-chip" id="about-version-chip">v2.4.
|
|
1487
|
+
<h2>nvstudio-mcp <span class="v2-chip" id="about-version-chip">v2.4.2</span></h2>
|
|
1488
1488
|
<p>Jembatan pintar berbasis <strong>Model Context Protocol (MCP)</strong> yang menghubungkan AI Agent (Antigravity IDE, Cursor, Claude Desktop, Windsurf) secara langsung ke dalam <strong>Roblox Studio</strong>.</p>
|
|
1489
1489
|
<div class="about-links">
|
|
1490
1490
|
<a class="about-link" href="https://github.com/Adiholick/nvstudio-mcp" target="_blank">
|
|
@@ -1499,7 +1499,7 @@
|
|
|
1499
1499
|
</div>
|
|
1500
1500
|
|
|
1501
1501
|
<div class="about-card">
|
|
1502
|
-
<h3>🚀 Fitur Baru v2.4.
|
|
1502
|
+
<h3>🚀 Fitur Baru v2.4.2</h3>
|
|
1503
1503
|
<ul>
|
|
1504
1504
|
<li><strong>🦴 NV-Rig Engine:</strong> Rigging headless presisi $O(1)$ untuk R6, R15, dan Custom Rig. Menyediakan inspeksi sendi (<code>inspect_rig</code>), pemindahan poros C0/C1 simultan anti-dislokasi (<code>edit_rig_joint</code>), auto-rigging instan (<code>auto_rig</code>), dan assembly welding senjata/prop (<code>weld_assembly</code>).</li>
|
|
1505
1505
|
<li><strong>🎬 NV-Animation Engine:</strong> Pembuatan animasi karakter halus alami (Walk, Slash, Punch, Idle, IK) langsung menjadi <code>KeyframeSequence</code> resmi dengan interpolasi Bezier (Cubic/Quad) dan penegakan batas anatomis aman tanpa glitch.</li>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
-- ══════════════════════════════════════════════════════════════════════
|
|
2
|
-
-- NVStudio MCP Plugin v2.4.
|
|
2
|
+
-- NVStudio MCP Plugin v2.4.2
|
|
3
3
|
-- Arsitektur: Dual-Mode WebSocket Duplex (Port 3055/ws) + Fallback Long-Polling
|
|
4
4
|
-- Plugin auto-connect saat dimuat via WebSocket native, dengan fallback otomatis
|
|
5
5
|
-- ke HTTP stream jika WebSocket tidak tersedia di environment Roblox Studio ini.
|
|
@@ -162,7 +162,7 @@ local function addSystemLog(msg, msgType)
|
|
|
162
162
|
local fullMsg = prefix .. msg
|
|
163
163
|
table.insert(ctx.recentLogs, fullMsg)
|
|
164
164
|
if #ctx.recentLogs > MAX_LOGS then table.remove(ctx.recentLogs, 1) end
|
|
165
|
-
if ui then ui:addLog(fullMsg, color) end
|
|
165
|
+
if ui then pcall(function() ui:addLog(fullMsg, color) end) end
|
|
166
166
|
end
|
|
167
167
|
LogService.MessageOut:Connect(addSystemLog)
|
|
168
168
|
|
|
@@ -237,8 +237,14 @@ local function processTask(taskData)
|
|
|
237
237
|
result.id = taskData.id
|
|
238
238
|
|
|
239
239
|
if ui then
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
pcall(function()
|
|
241
|
+
local color = result.status == "success" and Color3.fromRGB(100, 255, 100) or Color3.fromRGB(255, 100, 100)
|
|
242
|
+
local summary = tostring(result.result or result.error or "")
|
|
243
|
+
if #summary > 500 then
|
|
244
|
+
summary = string.sub(summary, 1, 500) .. " ... [Output besar]"
|
|
245
|
+
end
|
|
246
|
+
ui:addLog("[AI Result] " .. summary, color)
|
|
247
|
+
end)
|
|
242
248
|
end
|
|
243
249
|
|
|
244
250
|
return result
|
|
@@ -976,7 +976,7 @@ end
|
|
|
976
976
|
<BinaryString name="Tags"></BinaryString>
|
|
977
977
|
<token name="RunContext">0</token>
|
|
978
978
|
<ProtectedString name="Source"><![CDATA[-- ══════════════════════════════════════════════════════════════════════
|
|
979
|
-
-- NVStudio MCP Plugin v2.4.
|
|
979
|
+
-- NVStudio MCP Plugin v2.4.2
|
|
980
980
|
-- Arsitektur: Dual-Mode WebSocket Duplex (Port 3055/ws) + Fallback Long-Polling
|
|
981
981
|
-- Plugin auto-connect saat dimuat via WebSocket native, dengan fallback otomatis
|
|
982
982
|
-- ke HTTP stream jika WebSocket tidak tersedia di environment Roblox Studio ini.
|
|
@@ -1139,7 +1139,7 @@ local function addSystemLog(msg, msgType)
|
|
|
1139
1139
|
local fullMsg = prefix .. msg
|
|
1140
1140
|
table.insert(ctx.recentLogs, fullMsg)
|
|
1141
1141
|
if #ctx.recentLogs > MAX_LOGS then table.remove(ctx.recentLogs, 1) end
|
|
1142
|
-
if ui then ui:addLog(fullMsg, color) end
|
|
1142
|
+
if ui then pcall(function() ui:addLog(fullMsg, color) end) end
|
|
1143
1143
|
end
|
|
1144
1144
|
LogService.MessageOut:Connect(addSystemLog)
|
|
1145
1145
|
|
|
@@ -1214,8 +1214,14 @@ local function processTask(taskData)
|
|
|
1214
1214
|
result.id = taskData.id
|
|
1215
1215
|
|
|
1216
1216
|
if ui then
|
|
1217
|
-
|
|
1218
|
-
|
|
1217
|
+
pcall(function()
|
|
1218
|
+
local color = result.status == "success" and Color3.fromRGB(100, 255, 100) or Color3.fromRGB(255, 100, 100)
|
|
1219
|
+
local summary = tostring(result.result or result.error or "")
|
|
1220
|
+
if #summary > 500 then
|
|
1221
|
+
summary = string.sub(summary, 1, 500) .. " ... [Output besar]"
|
|
1222
|
+
end
|
|
1223
|
+
ui:addLog("[AI Result] " .. summary, color)
|
|
1224
|
+
end)
|
|
1219
1225
|
end
|
|
1220
1226
|
|
|
1221
1227
|
return result
|
|
@@ -5584,7 +5590,7 @@ function UIManager.init(pluginInstance, studioId)
|
|
|
5584
5590
|
|
|
5585
5591
|
-- Version
|
|
5586
5592
|
local versionLabel = Instance.new("TextLabel")
|
|
5587
|
-
versionLabel.Text = "v2.4.
|
|
5593
|
+
versionLabel.Text = "v2.4.2"
|
|
5588
5594
|
versionLabel.Font = Enum.Font.Gotham
|
|
5589
5595
|
versionLabel.TextSize = 11
|
|
5590
5596
|
versionLabel.TextColor3 = Color3.fromRGB(120, 120, 130)
|
|
@@ -5847,8 +5853,14 @@ end
|
|
|
5847
5853
|
-- Menambahkan baris log baru ke terminal GUI
|
|
5848
5854
|
-- ═══════════════════════════════════════════
|
|
5849
5855
|
function UIManager:addLog(text, color)
|
|
5856
|
+
local rawText = tostring(text or "")
|
|
5857
|
+
local MAX_LOG_LENGTH = 1000
|
|
5858
|
+
if #rawText > MAX_LOG_LENGTH then
|
|
5859
|
+
rawText = string.sub(rawText, 1, MAX_LOG_LENGTH) .. " ... [Terpotong " .. tostring(#rawText - MAX_LOG_LENGTH) .. " karakter]"
|
|
5860
|
+
end
|
|
5861
|
+
|
|
5850
5862
|
local timestamp = os.date("%H:%M:%S")
|
|
5851
|
-
local displayText = "[" .. timestamp .. "] " ..
|
|
5863
|
+
local displayText = "[" .. timestamp .. "] " .. rawText
|
|
5852
5864
|
|
|
5853
5865
|
local logLabel = Instance.new("TextLabel")
|
|
5854
5866
|
logLabel.Text = displayText
|
|
@@ -95,7 +95,7 @@ function UIManager.init(pluginInstance, studioId)
|
|
|
95
95
|
|
|
96
96
|
-- Version
|
|
97
97
|
local versionLabel = Instance.new("TextLabel")
|
|
98
|
-
versionLabel.Text = "v2.4.
|
|
98
|
+
versionLabel.Text = "v2.4.2"
|
|
99
99
|
versionLabel.Font = Enum.Font.Gotham
|
|
100
100
|
versionLabel.TextSize = 11
|
|
101
101
|
versionLabel.TextColor3 = Color3.fromRGB(120, 120, 130)
|
|
@@ -358,8 +358,14 @@ end
|
|
|
358
358
|
-- Menambahkan baris log baru ke terminal GUI
|
|
359
359
|
-- ═══════════════════════════════════════════
|
|
360
360
|
function UIManager:addLog(text, color)
|
|
361
|
+
local rawText = tostring(text or "")
|
|
362
|
+
local MAX_LOG_LENGTH = 1000
|
|
363
|
+
if #rawText > MAX_LOG_LENGTH then
|
|
364
|
+
rawText = string.sub(rawText, 1, MAX_LOG_LENGTH) .. " ... [Terpotong " .. tostring(#rawText - MAX_LOG_LENGTH) .. " karakter]"
|
|
365
|
+
end
|
|
366
|
+
|
|
361
367
|
local timestamp = os.date("%H:%M:%S")
|
|
362
|
-
local displayText = "[" .. timestamp .. "] " ..
|
|
368
|
+
local displayText = "[" .. timestamp .. "] " .. rawText
|
|
363
369
|
|
|
364
370
|
local logLabel = Instance.new("TextLabel")
|
|
365
371
|
logLabel.Text = displayText
|