@adiholick/nvstudio-mcp 1.1.0 → 2.0.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/dist/build-plugin.js +115 -0
- package/dist/index.js +16 -11
- package/dist/luau-validator.js +191 -0
- package/dist/roblox-bridge.js +27 -1
- package/dist/task-queue.js +4 -1
- package/package.json +6 -3
- package/public/index.html +360 -309
- package/studio-plugin/Main.server.lua +14 -3
- package/studio-plugin/nvstudio_mcp.rbxmx +1242 -1159
- package/studio-plugin/patch_script_source.lua +97 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
local HttpService = game:GetService("HttpService")
|
|
2
|
+
|
|
3
|
+
return function(targetInstance, data, ctx, targetPath)
|
|
4
|
+
if not targetInstance:IsA("LuaSourceContainer") then
|
|
5
|
+
return { status = "error", error = "Target BUKAN Script (ClassName: " .. targetInstance.ClassName .. ")." }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
local payload = nil
|
|
9
|
+
pcall(function()
|
|
10
|
+
payload = HttpService:JSONDecode(data)
|
|
11
|
+
end)
|
|
12
|
+
|
|
13
|
+
if not payload then
|
|
14
|
+
return { status = "error", error = "Payload data harus berupa JSON valid." }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
local currentSource = targetInstance.Source
|
|
18
|
+
local newSource = currentSource
|
|
19
|
+
local affectedLines = 0
|
|
20
|
+
|
|
21
|
+
-- Mode 1: Search & Replace Exact Chunk
|
|
22
|
+
if payload.target_content and payload.replacement_content then
|
|
23
|
+
local targetContent = payload.target_content
|
|
24
|
+
local replacementContent = payload.replacement_content
|
|
25
|
+
local allowMultiple = payload.allow_multiple or false
|
|
26
|
+
|
|
27
|
+
-- Escape magic characters for string.gsub if needed, or use string.find manually.
|
|
28
|
+
-- string.gsub doesn't do plain text replacement directly without escaping.
|
|
29
|
+
-- We'll write a plain text replace function.
|
|
30
|
+
|
|
31
|
+
local function plainReplace(str, pattern, repl, max)
|
|
32
|
+
local res = ""
|
|
33
|
+
local startIdx = 1
|
|
34
|
+
local count = 0
|
|
35
|
+
while true do
|
|
36
|
+
if max and count >= max then break end
|
|
37
|
+
local findStart, findEnd = string.find(str, pattern, startIdx, true) -- true for plain match
|
|
38
|
+
if not findStart then break end
|
|
39
|
+
|
|
40
|
+
res = res .. string.sub(str, startIdx, findStart - 1) .. repl
|
|
41
|
+
startIdx = findEnd + 1
|
|
42
|
+
count = count + 1
|
|
43
|
+
end
|
|
44
|
+
res = res .. string.sub(str, startIdx)
|
|
45
|
+
return res, count
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
local _, occurrences = plainReplace(currentSource, targetContent, replacementContent)
|
|
49
|
+
|
|
50
|
+
if occurrences == 0 then
|
|
51
|
+
return { status = "error", error = "target_content tidak ditemukan di dalam script." }
|
|
52
|
+
elseif occurrences > 1 and not allowMultiple then
|
|
53
|
+
return { status = "error", error = "target_content ditemukan " .. occurrences .. " kali. Tolong sertakan baris konteks lebih banyak agar unik, atau set allow_multiple = true." }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
newSource, affectedLines = plainReplace(currentSource, targetContent, replacementContent)
|
|
57
|
+
affectedLines = affectedLines -- not exact line count, but occurrences count
|
|
58
|
+
|
|
59
|
+
-- Mode 2: Line Range Replace
|
|
60
|
+
elseif payload.start_line and payload.end_line and payload.replacement_content then
|
|
61
|
+
local lines = string.split(currentSource, "\n")
|
|
62
|
+
local startLine = tonumber(payload.start_line)
|
|
63
|
+
local endLine = tonumber(payload.end_line)
|
|
64
|
+
|
|
65
|
+
if not startLine or not endLine or startLine < 1 or endLine > #lines or startLine > endLine then
|
|
66
|
+
return { status = "error", error = "Range baris tidak valid. Jumlah baris script: " .. #lines }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
local newLines = {}
|
|
70
|
+
for i = 1, startLine - 1 do
|
|
71
|
+
table.insert(newLines, lines[i])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
table.insert(newLines, payload.replacement_content)
|
|
75
|
+
|
|
76
|
+
for i = endLine + 1, #lines do
|
|
77
|
+
table.insert(newLines, lines[i])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
newSource = table.concat(newLines, "\n")
|
|
81
|
+
affectedLines = (endLine - startLine) + 1
|
|
82
|
+
else
|
|
83
|
+
return { status = "error", error = "Payload tidak lengkap. Butuh (target_content & replacement_content) atau (start_line, end_line & replacement_content)." }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
-- Simpan backup snapshot sebelum mengaplikasikan patch
|
|
87
|
+
ctx.scriptHistory[targetPath] = currentSource
|
|
88
|
+
|
|
89
|
+
-- Terapkan perubahan
|
|
90
|
+
targetInstance.Source = newSource
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
status = "success",
|
|
94
|
+
result = "Patch berhasil diterapkan pada '" .. targetInstance.Name .. "'. Perubahan diaplikasikan.",
|
|
95
|
+
affected_lines = affectedLines
|
|
96
|
+
}
|
|
97
|
+
end
|