@adiholick/nvstudio-mcp 2.2.2 → 2.3.0
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 +43 -47
- package/agent-plugin/mcp_config.json +8 -0
- package/agent-plugin/plugin.json +6 -0
- package/agent-plugin/rules/AGENTS.md +87 -0
- package/agent-plugin/skills/nvstudio-assets-terrain-guide/SKILL.md +27 -0
- package/agent-plugin/skills/nvstudio-gui-standards/SKILL.md +419 -0
- package/agent-plugin/skills/nvstudio-mcp-guide/SKILL.md +69 -0
- package/agent-plugin/skills/nvstudio-roblox-sync-guide/SKILL.md +16 -0
- package/dist/build-plugin.js +55 -0
- package/dist/index.js +988 -146
- package/dist/luau-validator.js +99 -34
- package/dist/roblox-bridge.js +390 -72
- package/dist/roblox-docs.js +264 -0
- package/dist/task-queue.js +57 -6
- package/dist/ws-gateway.js +579 -0
- package/package.json +7 -3
- package/public/index.html +634 -109
- package/studio-plugin/Main.server.lua +484 -53
- package/studio-plugin/batch_create_instances.lua +128 -0
- package/studio-plugin/batch_set_properties.lua +69 -0
- package/studio-plugin/get_properties.lua +25 -2
- package/studio-plugin/insert_asset.lua +85 -12
- package/studio-plugin/nvstudio_mcp.rbxmx +1393 -68
- package/studio-plugin/preview_asset.lua +99 -0
- package/studio-plugin/scan_security.lua +81 -0
- package/studio-plugin/security_scanner.lua +346 -0
- package/studio-plugin/set_properties.lua +10 -0
- package/studio-plugin/ui_manager.lua +1 -1
package/dist/luau-validator.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateLuauSyntax = validateLuauSyntax;
|
|
4
|
+
/**
|
|
5
|
+
* Heuristic pre-commit syntax validator for Luau.
|
|
6
|
+
* Validates bracket parity, string literals, multiline comments,
|
|
7
|
+
* and block keywords (function, do, statement if ... then, repeat ... until, end).
|
|
8
|
+
*/
|
|
4
9
|
function validateLuauSyntax(source) {
|
|
5
10
|
const lines = source.split('\n');
|
|
6
|
-
// Stack for blocks: function, do, if, for, while, repeat
|
|
7
|
-
// We'll keep it simple: just count block openers vs block closers (end, until)
|
|
8
|
-
// Note: This is a heuristic pre-commit check. It doesn't replace a full AST parser,
|
|
9
|
-
// Bracket stacks
|
|
10
11
|
let parenDepth = 0; // ()
|
|
11
12
|
let braceDepth = 0; // {}
|
|
12
13
|
let bracketDepth = 0; // []
|
|
14
|
+
let blockDepth = 0; // function, do, if ... then -> end
|
|
15
|
+
let repeatDepth = 0; // repeat -> until
|
|
13
16
|
let inString = false;
|
|
14
17
|
let stringChar = '';
|
|
15
18
|
let inMultilineString = false;
|
|
@@ -18,10 +21,11 @@ function validateLuauSyntax(source) {
|
|
|
18
21
|
for (let i = 0; i < lines.length; i++) {
|
|
19
22
|
const line = lines[i];
|
|
20
23
|
let j = 0;
|
|
24
|
+
const lineTokens = [];
|
|
21
25
|
while (j < line.length) {
|
|
22
26
|
const char = line[j];
|
|
23
27
|
const nextChar = line[j + 1] || '';
|
|
24
|
-
//
|
|
28
|
+
// Multiline comment start: --[[ or --[===[
|
|
25
29
|
if (!inString && !inMultilineString && !inMultilineComment) {
|
|
26
30
|
if (char === '-' && nextChar === '-') {
|
|
27
31
|
const nextNextChar = line[j + 2] || '';
|
|
@@ -39,7 +43,7 @@ function validateLuauSyntax(source) {
|
|
|
39
43
|
continue;
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
|
-
// Single
|
|
46
|
+
// Single-line comment, ignore rest of line
|
|
43
47
|
break;
|
|
44
48
|
}
|
|
45
49
|
}
|
|
@@ -60,7 +64,7 @@ function validateLuauSyntax(source) {
|
|
|
60
64
|
j++;
|
|
61
65
|
continue;
|
|
62
66
|
}
|
|
63
|
-
//
|
|
67
|
+
// String literals
|
|
64
68
|
if (!inString && !inMultilineString) {
|
|
65
69
|
if (char === '"' || char === "'") {
|
|
66
70
|
inString = true;
|
|
@@ -81,10 +85,6 @@ function validateLuauSyntax(source) {
|
|
|
81
85
|
j = k + 1;
|
|
82
86
|
continue;
|
|
83
87
|
}
|
|
84
|
-
// If it ended at end of line, we can't reliably detect it. Let's just avoid bracket counting
|
|
85
|
-
if (line[k] === undefined) {
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
if (inString) {
|
|
@@ -115,36 +115,97 @@ function validateLuauSyntax(source) {
|
|
|
115
115
|
j++;
|
|
116
116
|
continue;
|
|
117
117
|
}
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
118
|
+
// Outside strings & comments: collect bracket depth & tokens
|
|
119
|
+
if (char === '(') {
|
|
120
|
+
parenDepth++;
|
|
121
|
+
lineTokens.push('(');
|
|
122
|
+
}
|
|
123
|
+
else if (char === ')') {
|
|
124
|
+
parenDepth--;
|
|
125
|
+
lineTokens.push(')');
|
|
126
|
+
if (parenDepth < 0)
|
|
127
|
+
return { valid: false, error: 'Kelebihan tutup kurung ")"', line: i + 1 };
|
|
128
|
+
}
|
|
129
|
+
else if (char === '{') {
|
|
130
|
+
braceDepth++;
|
|
131
|
+
lineTokens.push('{');
|
|
132
|
+
}
|
|
133
|
+
else if (char === '}') {
|
|
134
|
+
braceDepth--;
|
|
135
|
+
lineTokens.push('}');
|
|
136
|
+
if (braceDepth < 0)
|
|
137
|
+
return { valid: false, error: 'Kelebihan tutup kurawal "}"', line: i + 1 };
|
|
138
|
+
}
|
|
139
|
+
else if (char === '[') {
|
|
140
|
+
bracketDepth++;
|
|
141
|
+
lineTokens.push('[');
|
|
142
|
+
}
|
|
143
|
+
else if (char === ']') {
|
|
144
|
+
bracketDepth--;
|
|
145
|
+
lineTokens.push(']');
|
|
146
|
+
if (bracketDepth < 0)
|
|
147
|
+
return { valid: false, error: 'Kelebihan tutup siku "]"', line: i + 1 };
|
|
148
|
+
}
|
|
149
|
+
else if (char === '=') {
|
|
150
|
+
lineTokens.push('=');
|
|
151
|
+
}
|
|
152
|
+
else if (char === ',') {
|
|
153
|
+
lineTokens.push(',');
|
|
154
|
+
}
|
|
155
|
+
else if (/[a-zA-Z_]/.test(char)) {
|
|
156
|
+
let start = j;
|
|
157
|
+
while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) {
|
|
158
|
+
j++;
|
|
141
159
|
}
|
|
160
|
+
lineTokens.push(line.substring(start, j));
|
|
161
|
+
continue;
|
|
142
162
|
}
|
|
143
163
|
j++;
|
|
144
164
|
}
|
|
145
165
|
if (inString) {
|
|
146
166
|
return { valid: false, error: 'String tidak ditutup (unclosed string literal)', line: i + 1 };
|
|
147
167
|
}
|
|
168
|
+
// Process line tokens for block balance
|
|
169
|
+
let statementIfCount = 0;
|
|
170
|
+
for (let t = 0; t < lineTokens.length; t++) {
|
|
171
|
+
const tok = lineTokens[t];
|
|
172
|
+
const prevTok = t > 0 ? lineTokens[t - 1] : null;
|
|
173
|
+
if (tok === 'function') {
|
|
174
|
+
blockDepth++;
|
|
175
|
+
}
|
|
176
|
+
else if (tok === 'do') {
|
|
177
|
+
blockDepth++;
|
|
178
|
+
}
|
|
179
|
+
else if (tok === 'if') {
|
|
180
|
+
// Luau expression if is preceded by '=', 'return', '(', ',', '{', '[', 'and', 'or', 'not'
|
|
181
|
+
const isExpr = prevTok && ['=', 'return', '(', ',', '{', '[', 'and', 'or', 'not'].includes(prevTok);
|
|
182
|
+
if (!isExpr) {
|
|
183
|
+
statementIfCount++;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else if (tok === 'then') {
|
|
187
|
+
const isElseIf = lineTokens.includes('elseif');
|
|
188
|
+
if (!isElseIf) {
|
|
189
|
+
if (statementIfCount > 0) {
|
|
190
|
+
blockDepth++;
|
|
191
|
+
statementIfCount--;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (tok === 'repeat') {
|
|
196
|
+
repeatDepth++;
|
|
197
|
+
}
|
|
198
|
+
else if (tok === 'until') {
|
|
199
|
+
repeatDepth--;
|
|
200
|
+
if (repeatDepth < 0)
|
|
201
|
+
return { valid: false, error: 'Kelebihan kata kunci "until"', line: i + 1 };
|
|
202
|
+
}
|
|
203
|
+
else if (tok === 'end') {
|
|
204
|
+
blockDepth--;
|
|
205
|
+
if (blockDepth < 0)
|
|
206
|
+
return { valid: false, error: 'Kelebihan kata kunci "end"', line: i + 1 };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
148
209
|
}
|
|
149
210
|
if (inMultilineString)
|
|
150
211
|
return { valid: false, error: 'Multiline string tidak ditutup (unclosed [[ ]])' };
|
|
@@ -156,5 +217,9 @@ function validateLuauSyntax(source) {
|
|
|
156
217
|
return { valid: false, error: 'Kekurangan tutup kurawal "}"' };
|
|
157
218
|
if (bracketDepth > 0)
|
|
158
219
|
return { valid: false, error: 'Kekurangan tutup siku "]"' };
|
|
220
|
+
if (repeatDepth > 0)
|
|
221
|
+
return { valid: false, error: 'Kekurangan kata kunci "until"' };
|
|
222
|
+
if (blockDepth > 0)
|
|
223
|
+
return { valid: false, error: 'Kekurangan kata kunci "end" (blok tidak ditutup)' };
|
|
159
224
|
return { valid: true };
|
|
160
225
|
}
|