@weppy/roblox-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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +17 -0
- package/README.md +3 -5
- package/docs/en/installation/README.md +2 -2
- package/docs/es/README.md +1 -3
- package/docs/es/installation/README.md +2 -2
- package/docs/id/README.md +0 -2
- package/docs/id/installation/README.md +2 -2
- package/docs/installer/assets/index-B4Gp7BPj.js +63 -0
- package/docs/installer/assets/index-B7mvmOPt.css +1 -0
- package/docs/installer/index.html +14 -0
- package/docs/installer/manifest.webmanifest +15 -0
- package/docs/installer/sw.js +7 -0
- package/docs/installer/wrox-icon.png +0 -0
- package/docs/ja/README.md +0 -2
- package/docs/ja/installation/README.md +1 -1
- package/docs/ko/README.md +3 -5
- package/docs/ko/installation/README.md +2 -2
- package/docs/pt-br/README.md +1 -3
- package/docs/pt-br/installation/README.md +2 -2
- package/install.ps1 +434 -4
- package/install.sh +439 -4
- package/llms-full.txt +14 -2
- package/llms.txt +9 -3
- package/package.json +1 -1
- package/plugins/weppy-roblox-mcp/.claude-plugin/plugin.json +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ChangelogDetailPage-D7eMrarv.js → ChangelogDetailPage-CGK59Jsx.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ChangelogPage-DFCCRyyK.js → ChangelogPage-oNm6ratx.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ConfirmModal-BmRJ2JXZ.js → ConfirmModal-Dtak3Vnq.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ConnectionPage-CiaCY026.js → ConnectionPage-CjLtImxr.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{InfoLabel-CCDWZLC9.js → InfoLabel-CLvjiyTG.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{OverviewPage-BHpt3LI2.js → OverviewPage-BdF0Ve7h.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{PlaytestPage-CNwwI5Ro.js → PlaytestPage-cQMWlAOS.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{PropertyDiff-DIplDn-J.js → PropertyDiff-BnOZxkTS.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{SettingsPage-CPqQYZPN.js → SettingsPage-C-QX0AY-.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{StatusBadge-C8VKAPpk.js → StatusBadge-A9U9m2LQ.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{SyncPage-DTSKbpio.js → SyncPage-BAS0cXRM.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{TierComparison-7ofkPwj3.js → TierComparison-BA_L4c9p.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{TierPromoProgress-SnRUjAPh.js → TierPromoProgress-Dq6ofjr2.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ToolsPage-CrdNh3D9.js → ToolsPage-C_tMIyix.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{index-DGGmfli1.js → index-OH9mpHwW.js} +2 -2
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{useLiveUptime-BnXeLpOw.js → useLiveUptime-Df1ECedb.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/index.html +1 -1
- package/plugins/weppy-roblox-mcp/dist/index.js +63 -65
- package/plugins/weppy-roblox-mcp/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
package/install.sh
CHANGED
|
@@ -117,7 +117,7 @@ try {
|
|
|
117
117
|
' >/dev/null 2>&1
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
#
|
|
120
|
+
# Antigravity 설정에 canonical mcpServers 래퍼로 MCP 서버를 추가하고 legacy flat key를 정리
|
|
121
121
|
add_antigravity_mcp_config() {
|
|
122
122
|
local config_path="$1"
|
|
123
123
|
local parent_dir
|
|
@@ -128,7 +128,20 @@ const fs = require("fs");
|
|
|
128
128
|
const configPath = process.env.MCP_CONFIG_PATH;
|
|
129
129
|
let config = {};
|
|
130
130
|
try { config = JSON.parse(fs.readFileSync(configPath, "utf8")); } catch {}
|
|
131
|
-
config
|
|
131
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
132
|
+
config = {};
|
|
133
|
+
}
|
|
134
|
+
const mcpServers = config.mcpServers;
|
|
135
|
+
if (mcpServers !== undefined && (typeof mcpServers !== "object" || mcpServers === null || Array.isArray(mcpServers))) {
|
|
136
|
+
throw new Error("Antigravity mcpServers must be an object");
|
|
137
|
+
}
|
|
138
|
+
const next = { ...config };
|
|
139
|
+
delete next["weppy-roblox-mcp"];
|
|
140
|
+
next.mcpServers = {
|
|
141
|
+
...(mcpServers || {}),
|
|
142
|
+
"weppy-roblox-mcp": { command: "npx", args: ["-y", "@weppy/roblox-mcp"] }
|
|
143
|
+
};
|
|
144
|
+
config = next;
|
|
132
145
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
133
146
|
'
|
|
134
147
|
}
|
|
@@ -141,9 +154,24 @@ is_antigravity_mcp_configured() {
|
|
|
141
154
|
MCP_CONFIG_PATH="$config_path" node -e '
|
|
142
155
|
const fs = require("fs");
|
|
143
156
|
const configPath = process.env.MCP_CONFIG_PATH;
|
|
157
|
+
function isJsonObject(value) {
|
|
158
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
159
|
+
}
|
|
160
|
+
function hasExpectedCommandShape(value) {
|
|
161
|
+
return (
|
|
162
|
+
isJsonObject(value) &&
|
|
163
|
+
value.command === "npx" &&
|
|
164
|
+
Array.isArray(value.args) &&
|
|
165
|
+
value.args.length === 2 &&
|
|
166
|
+
value.args[0] === "-y" &&
|
|
167
|
+
value.args[1] === "@weppy/roblox-mcp"
|
|
168
|
+
);
|
|
169
|
+
}
|
|
144
170
|
try {
|
|
145
171
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
146
|
-
|
|
172
|
+
const canonical = config?.mcpServers?.["weppy-roblox-mcp"];
|
|
173
|
+
const hasLegacyFlatKey = Object.prototype.hasOwnProperty.call(config, "weppy-roblox-mcp");
|
|
174
|
+
process.exit(hasExpectedCommandShape(canonical) && !hasLegacyFlatKey ? 0 : 1);
|
|
147
175
|
} catch {
|
|
148
176
|
process.exit(1);
|
|
149
177
|
}
|
|
@@ -154,7 +182,414 @@ is_codex_config_configured() {
|
|
|
154
182
|
local config_path="$1"
|
|
155
183
|
|
|
156
184
|
[ -f "$config_path" ] || return 1
|
|
157
|
-
|
|
185
|
+
MCP_CODEX_CONFIG_PATH="$config_path" node <<'NODE' >/dev/null 2>&1
|
|
186
|
+
const fs = require("fs");
|
|
187
|
+
|
|
188
|
+
const configPath = process.env.MCP_CODEX_CONFIG_PATH;
|
|
189
|
+
const serverName = "weppy-roblox-mcp";
|
|
190
|
+
const expectedCommand = "npx";
|
|
191
|
+
const expectedArgs = ["-y", "@weppy/roblox-mcp"];
|
|
192
|
+
const headerPattern = new RegExp(
|
|
193
|
+
"^\\s*\\[\\s*mcp_servers\\." + serverName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*\\]\\s*(?:#.*)?$",
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
function stripCommentOutsideStrings(line) {
|
|
197
|
+
let inSingle = false;
|
|
198
|
+
let inDouble = false;
|
|
199
|
+
let escaped = false;
|
|
200
|
+
|
|
201
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
202
|
+
const char = line[index];
|
|
203
|
+
|
|
204
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
205
|
+
inDouble = !inDouble;
|
|
206
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
207
|
+
inSingle = !inSingle;
|
|
208
|
+
} else if (char === "#" && !inSingle && !inDouble) {
|
|
209
|
+
return line.slice(0, index).trimEnd();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
escaped = char === "\\" && !escaped;
|
|
213
|
+
if (char !== "\\") {
|
|
214
|
+
escaped = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return line.trimEnd();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function countTripleQuoteToggles(line, quote) {
|
|
222
|
+
let count = 0;
|
|
223
|
+
let inSingle = false;
|
|
224
|
+
let inDouble = false;
|
|
225
|
+
let escaped = false;
|
|
226
|
+
|
|
227
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
228
|
+
const char = line[index] ?? "";
|
|
229
|
+
const nextThree = line.slice(index, index + 3);
|
|
230
|
+
const isOutsideStrings = !inSingle && !inDouble;
|
|
231
|
+
|
|
232
|
+
if (isOutsideStrings && nextThree === quote.repeat(3)) {
|
|
233
|
+
count += 1;
|
|
234
|
+
index += 2;
|
|
235
|
+
escaped = false;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
240
|
+
inDouble = !inDouble;
|
|
241
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
242
|
+
inSingle = !inSingle;
|
|
243
|
+
} else if (char === "#" && !inSingle && !inDouble) {
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
escaped = char === "\\" && !escaped;
|
|
248
|
+
if (char !== "\\") {
|
|
249
|
+
escaped = false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return count;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function advanceTripleQuoteState(line, state) {
|
|
257
|
+
const next = { ...state };
|
|
258
|
+
const tripleDoubleCount = countTripleQuoteToggles(line, '"');
|
|
259
|
+
const tripleSingleCount = countTripleQuoteToggles(line, "'");
|
|
260
|
+
|
|
261
|
+
if (!next.inTripleSingle && tripleDoubleCount % 2 === 1) {
|
|
262
|
+
next.inTripleDouble = !next.inTripleDouble;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!next.inTripleDouble && tripleSingleCount % 2 === 1) {
|
|
266
|
+
next.inTripleSingle = !next.inTripleSingle;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return next;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isTomlTableHeaderLine(line) {
|
|
273
|
+
const normalized = stripCommentOutsideStrings(line).trim();
|
|
274
|
+
|
|
275
|
+
if (normalized.length === 0) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return /^\[\[.*\]\]$/.test(normalized) || /^\[.*\]$/.test(normalized);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function findAllCodexBlocks(source) {
|
|
283
|
+
const lines = source.split("\n");
|
|
284
|
+
const blocks = [];
|
|
285
|
+
let activeLines = null;
|
|
286
|
+
let state = {
|
|
287
|
+
inTripleDouble: false,
|
|
288
|
+
inTripleSingle: false,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
const isHeaderCandidate = !state.inTripleDouble && !state.inTripleSingle && isTomlTableHeaderLine(line);
|
|
293
|
+
const isCodexHeader = isHeaderCandidate && headerPattern.test(line);
|
|
294
|
+
|
|
295
|
+
if (isCodexHeader) {
|
|
296
|
+
if (activeLines !== null) {
|
|
297
|
+
blocks.push(activeLines.join("\n").trim());
|
|
298
|
+
}
|
|
299
|
+
activeLines = [line];
|
|
300
|
+
} else if (activeLines !== null && isHeaderCandidate) {
|
|
301
|
+
blocks.push(activeLines.join("\n").trim());
|
|
302
|
+
activeLines = null;
|
|
303
|
+
} else if (activeLines !== null) {
|
|
304
|
+
activeLines.push(line);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
state = advanceTripleQuoteState(line, state);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (activeLines !== null) {
|
|
311
|
+
blocks.push(activeLines.join("\n").trim());
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return blocks;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function parseStringAssignment(value, key) {
|
|
318
|
+
const match = new RegExp("^\\s*" + key + "\\s*=\\s*([\"'])([^\"']+)\\1\\s*$").exec(value);
|
|
319
|
+
return match ? match[2] : null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function parseTomlStringArray(value) {
|
|
323
|
+
const match = /^\s*args\s*=\s*\[(.*)\]\s*$/ms.exec(value.trim());
|
|
324
|
+
|
|
325
|
+
if (match === null) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const body = match[1] ?? "";
|
|
330
|
+
const values = [];
|
|
331
|
+
let cursor = 0;
|
|
332
|
+
let expectValue = true;
|
|
333
|
+
|
|
334
|
+
while (cursor < body.length) {
|
|
335
|
+
while (cursor < body.length && /\s/.test(body[cursor] ?? "")) {
|
|
336
|
+
cursor += 1;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (cursor >= body.length) {
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!expectValue) {
|
|
344
|
+
if (body[cursor] !== ",") {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
cursor += 1;
|
|
348
|
+
expectValue = true;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const quote = body[cursor];
|
|
353
|
+
if (quote !== '"' && quote !== "'") {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
cursor += 1;
|
|
358
|
+
let token = "";
|
|
359
|
+
let escaped = false;
|
|
360
|
+
|
|
361
|
+
while (cursor < body.length) {
|
|
362
|
+
const char = body[cursor] ?? "";
|
|
363
|
+
|
|
364
|
+
if (char === quote && !escaped) {
|
|
365
|
+
cursor += 1;
|
|
366
|
+
values.push(token);
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
token += char;
|
|
371
|
+
escaped = char === "\\" && !escaped;
|
|
372
|
+
if (char !== "\\") {
|
|
373
|
+
escaped = false;
|
|
374
|
+
}
|
|
375
|
+
cursor += 1;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (cursor > body.length) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
expectValue = false;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const leftover = body.slice(cursor).trim();
|
|
386
|
+
if (leftover === ",") {
|
|
387
|
+
return values;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return leftover.length === 0 ? values : null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function collectArrayLines(lines, startIndex) {
|
|
394
|
+
const collected = [stripCommentOutsideStrings(lines[startIndex] ?? "")];
|
|
395
|
+
let bracketDepth = 0;
|
|
396
|
+
let inSingle = false;
|
|
397
|
+
let inDouble = false;
|
|
398
|
+
let escaped = false;
|
|
399
|
+
|
|
400
|
+
for (let lineIndex = startIndex; lineIndex < lines.length; lineIndex += 1) {
|
|
401
|
+
const sanitized = stripCommentOutsideStrings(lines[lineIndex] ?? "");
|
|
402
|
+
if (lineIndex !== startIndex) {
|
|
403
|
+
collected.push(sanitized);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
for (let index = 0; index < sanitized.length; index += 1) {
|
|
407
|
+
const char = sanitized[index] ?? "";
|
|
408
|
+
|
|
409
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
410
|
+
inDouble = !inDouble;
|
|
411
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
412
|
+
inSingle = !inSingle;
|
|
413
|
+
} else if (!inSingle && !inDouble) {
|
|
414
|
+
if (char === "[") {
|
|
415
|
+
bracketDepth += 1;
|
|
416
|
+
} else if (char === "]") {
|
|
417
|
+
bracketDepth -= 1;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
escaped = char === "\\" && !escaped;
|
|
422
|
+
if (char !== "\\") {
|
|
423
|
+
escaped = false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (bracketDepth <= 0) {
|
|
428
|
+
return {
|
|
429
|
+
nextIndex: lineIndex,
|
|
430
|
+
text: collected.join("\n"),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function parseCodexBlock(blockContent) {
|
|
439
|
+
const lines = blockContent.split("\n");
|
|
440
|
+
let command = null;
|
|
441
|
+
let args = null;
|
|
442
|
+
let hasConflict = false;
|
|
443
|
+
let inTripleDouble = false;
|
|
444
|
+
let inTripleSingle = false;
|
|
445
|
+
|
|
446
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
447
|
+
const line = lines[index] ?? "";
|
|
448
|
+
const sanitized = stripCommentOutsideStrings(line);
|
|
449
|
+
const trimmed = sanitized.trim();
|
|
450
|
+
|
|
451
|
+
if (inTripleDouble) {
|
|
452
|
+
if (countTripleQuoteToggles(sanitized, '"') % 2 === 1) {
|
|
453
|
+
inTripleDouble = false;
|
|
454
|
+
}
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (inTripleSingle) {
|
|
459
|
+
if (countTripleQuoteToggles(sanitized, "'") % 2 === 1) {
|
|
460
|
+
inTripleSingle = false;
|
|
461
|
+
}
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (countTripleQuoteToggles(sanitized, '"') % 2 === 1) {
|
|
466
|
+
inTripleDouble = true;
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (countTripleQuoteToggles(sanitized, "'") % 2 === 1) {
|
|
471
|
+
inTripleSingle = true;
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (trimmed.length === 0) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (/^command\s*=/.test(trimmed)) {
|
|
480
|
+
const parsedCommand = parseStringAssignment(trimmed, "command");
|
|
481
|
+
if (command !== null || parsedCommand === null) {
|
|
482
|
+
hasConflict = true;
|
|
483
|
+
} else {
|
|
484
|
+
command = parsedCommand;
|
|
485
|
+
}
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (/^args\s*=/.test(trimmed)) {
|
|
490
|
+
const collected = collectArrayLines(lines, index);
|
|
491
|
+
const parsedArgs = collected === null ? null : parseTomlStringArray(collected.text);
|
|
492
|
+
|
|
493
|
+
if (args !== null || parsedArgs === null || collected === null) {
|
|
494
|
+
hasConflict = true;
|
|
495
|
+
} else {
|
|
496
|
+
args = parsedArgs;
|
|
497
|
+
index = collected.nextIndex;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
args,
|
|
504
|
+
command,
|
|
505
|
+
hasConflict,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function isStructurallySafe(source) {
|
|
510
|
+
let bracketDepth = 0;
|
|
511
|
+
let braceDepth = 0;
|
|
512
|
+
let inSingle = false;
|
|
513
|
+
let inDouble = false;
|
|
514
|
+
let escaped = false;
|
|
515
|
+
let tripleState = {
|
|
516
|
+
inTripleDouble: false,
|
|
517
|
+
inTripleSingle: false,
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
for (const line of source.split("\n")) {
|
|
521
|
+
tripleState = advanceTripleQuoteState(line, tripleState);
|
|
522
|
+
|
|
523
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
524
|
+
const char = line[index] ?? "";
|
|
525
|
+
|
|
526
|
+
if (!inSingle && !inDouble && char === "#") {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
531
|
+
inDouble = !inDouble;
|
|
532
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
533
|
+
inSingle = !inSingle;
|
|
534
|
+
} else if (!inSingle && !inDouble) {
|
|
535
|
+
if (char === "[") {
|
|
536
|
+
bracketDepth += 1;
|
|
537
|
+
} else if (char === "]") {
|
|
538
|
+
bracketDepth -= 1;
|
|
539
|
+
if (bracketDepth < 0) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
} else if (char === "{") {
|
|
543
|
+
braceDepth += 1;
|
|
544
|
+
} else if (char === "}") {
|
|
545
|
+
braceDepth -= 1;
|
|
546
|
+
if (braceDepth < 0) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
escaped = char === "\\" && !escaped;
|
|
553
|
+
if (char !== "\\") {
|
|
554
|
+
escaped = false;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
!tripleState.inTripleDouble &&
|
|
561
|
+
!tripleState.inTripleSingle &&
|
|
562
|
+
bracketDepth === 0 &&
|
|
563
|
+
braceDepth === 0 &&
|
|
564
|
+
!inSingle &&
|
|
565
|
+
!inDouble
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
try {
|
|
570
|
+
const source = fs.readFileSync(configPath, "utf8");
|
|
571
|
+
if (!isStructurallySafe(source)) {
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const blocks = findAllCodexBlocks(source);
|
|
576
|
+
if (blocks.length !== 1) {
|
|
577
|
+
process.exit(1);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const parsed = parseCodexBlock(blocks[0]);
|
|
581
|
+
const isConfigured =
|
|
582
|
+
!parsed.hasConflict &&
|
|
583
|
+
parsed.command === expectedCommand &&
|
|
584
|
+
Array.isArray(parsed.args) &&
|
|
585
|
+
parsed.args.length === expectedArgs.length &&
|
|
586
|
+
parsed.args.every((entry, index) => entry === expectedArgs[index]);
|
|
587
|
+
|
|
588
|
+
process.exit(isConfigured ? 0 : 1);
|
|
589
|
+
} catch {
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
NODE
|
|
158
593
|
}
|
|
159
594
|
|
|
160
595
|
resolve_optional_cli_command() {
|
package/llms-full.txt
CHANGED
|
@@ -21,9 +21,21 @@ Roblox Studio Plugin ← Executes commands inside Studio
|
|
|
21
21
|
|
|
22
22
|
When an AI app says "Create a blue part", the MCP server converts this request, and the Roblox Studio plugin actually creates the part.
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Web Installer (Recommended)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Open the installer page in Chrome, Edge, or Arc for one-click setup:
|
|
27
|
+
|
|
28
|
+
https://hope1026.github.io/weppy-roblox-mcp/installer/
|
|
29
|
+
|
|
30
|
+
It writes the supported AI app config for `npx -y @weppy/roblox-mcp` first.
|
|
31
|
+
|
|
32
|
+
After you reopen the AI app, the first MCP run fetches the package through `npx` and auto-installs the Roblox Studio plugin.
|
|
33
|
+
|
|
34
|
+
For Safari or Firefox, use the installer page as a guide or continue with the manual install below.
|
|
35
|
+
|
|
36
|
+
## One-Line Install (Fallback)
|
|
37
|
+
|
|
38
|
+
Advanced users can install everything in one command:
|
|
27
39
|
|
|
28
40
|
```bash
|
|
29
41
|
# macOS / Linux
|
package/llms.txt
CHANGED
|
@@ -21,7 +21,11 @@ terrain, and more — inside a live Studio session.
|
|
|
21
21
|
|
|
22
22
|
## Installation
|
|
23
23
|
|
|
24
|
-
**
|
|
24
|
+
**Web installer** (recommended one-click setup for Chrome, Edge, and Arc):
|
|
25
|
+
|
|
26
|
+
https://hope1026.github.io/weppy-roblox-mcp/installer/
|
|
27
|
+
|
|
28
|
+
**One-line install** (advanced fallback):
|
|
25
29
|
|
|
26
30
|
```bash
|
|
27
31
|
# macOS / Linux
|
|
@@ -31,8 +35,10 @@ curl -fsSL https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/inst
|
|
|
31
35
|
irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1 | iex
|
|
32
36
|
```
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
Safari / Firefox users should follow the installer page guide or open the installation docs.
|
|
39
|
+
|
|
40
|
+
Manual alternative:
|
|
41
|
+
1. Install Roblox Studio plugin via the installation guide
|
|
36
42
|
2. Register MCP server: `npx -y @weppy/roblox-mcp`
|
|
37
43
|
|
|
38
44
|
## Tiers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weppy/roblox-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "MCP (Model Context Protocol) server for Roblox Studio integration - enables AI coding agents to interact with Roblox Studio in real-time",
|
|
5
5
|
"main": "plugins/weppy-roblox-mcp/dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r,a as R,u as M,b as B,c as D,j as e,T as m}from"./index-DGGmfli1.js";import{I as V}from"./InfoLabel-CCDWZLC9.js";import{D as F,P as G}from"./PropertyDiff-DIplDn-J.js";function P(t){const s={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const l of t)switch(l.category){case"script":l.changeType==="create"?s.scriptsCreated++:s.scriptsModified++;break;case"instance":l.changeType==="create"?s.instancesCreated++:l.changeType==="delete"?s.instancesDeleted++:l.changeType==="move"&&s.instancesMoved++;break;case"property":s.propertiesChanged++;break;case"lighting":s.lightingChanged=!0;break;case"terrain":s.terrainChanged=!0;break;case"asset":s.assetsInserted++;break}return s}function U(t){const[s,l]=r.useState(""),[a,d]=r.useState(""),[u,q]=r.useState(),[w,y]=r.useState("completed"),[E,I]=r.useState([]),[O,L]=r.useState([]),[f,x]=r.useState([]),[p,j]=r.useState(),[_,b]=r.useState(),[v,S]=r.useState(),[C,N]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[T,g]=r.useState(!0),[k,h]=r.useState(null),i=r.useCallback(async()=>{if(t){g(!0),h(null);try{const[c,o]=await Promise.all([R.get(`/api/dashboard/changelog/${t}`),R.get(`/api/dashboard/changelog/${t}/changes`)]);l(c.entryId),d(c.startTime),q(c.endTime),y(c.status),I(c.entries),L(c.failures),j(c.contextSummary),b(c.replayMetadata),S(c.verificationSummary),x(o.changes),N(P(o.changes))}catch(c){h(c instanceof Error?c.message:"Failed to load changelog detail")}finally{g(!1)}}},[t]);return r.useEffect(()=>{i()},[i]),{entryId:s,startTime:a,endTime:u,status:w,entries:E,failures:O,changes:f,changeSummary:C,contextSummary:p,replayMetadata:_,verificationSummary:v,loading:T,error:k,refresh:i}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function H(t){return z[t]??"❓"}const J="_page_q2jbi_2",W="_header_q2jbi_10",Y="_backLink_q2jbi_16",Q="_headerTitle_q2jbi_29",X="_headerTime_q2jbi_37",Z="_statusActive_q2jbi_44",ee="_statusCompleted_q2jbi_49",te="_section_q2jbi_54",ne="_sectionTitle_q2jbi_61",ae="_summaryGrid_q2jbi_74",ie="_summaryCard_q2jbi_80",se="_summaryCardActive_q2jbi_94",ce="_summaryIcon_q2jbi_99",re="_summaryCount_q2jbi_105",oe="_summaryLabel_q2jbi_112",le="_contextGrid_q2jbi_121",de="_contextRow_q2jbi_127",me="_contextKey_q2jbi_133",ge="_contextValue_q2jbi_141",he="_timelineFilter_q2jbi_149",ue="_filterLabel_q2jbi_156",ye="_filterSelect_q2jbi_162",fe="_timeline_q2jbi_149",xe="_timelineEntry_q2jbi_182",pe="_timelineTime_q2jbi_199",je="_timelineIcon_q2jbi_207",_e="_timelineBody_q2jbi_212",be="_timelineSummary_q2jbi_217",ve="_timelineTarget_q2jbi_224",Se="_timelineConfidence_q2jbi_231",Ce="_confidenceExact_q2jbi_240",Ne="_confidencePartial_q2jbi_245",Te="_confidenceAfterOnly_q2jbi_250",ke="_confidenceIntentOnly_q2jbi_255",qe="_confidenceUnknown_q2jbi_260",we="_timelineExpanded_q2jbi_266",Ee="_empty_q2jbi_338",Ie="_loading_q2jbi_347",Oe="_error_q2jbi_356",n={page:J,header:W,backLink:Y,headerTitle:Q,headerTime:X,statusActive:Z,statusCompleted:ee,section:te,sectionTitle:ne,summaryGrid:ae,summaryCard:ie,summaryCardActive:se,summaryIcon:ce,summaryCount:re,summaryLabel:oe,contextGrid:le,contextRow:de,contextKey:me,contextValue:ge,timelineFilter:he,filterLabel:ue,filterSelect:ye,timeline:fe,timelineEntry:xe,timelineTime:pe,timelineIcon:je,timelineBody:_e,timelineSummary:be,timelineTarget:ve,timelineConfidence:Se,confidenceExact:Ce,confidencePartial:Ne,confidenceAfterOnly:Te,confidenceIntentOnly:ke,confidenceUnknown:qe,timelineExpanded:we,empty:Ee,loading:Ie,error:Oe},$=[{key:"script",icon:"📝",labelKey:"changelog.category.script"},{key:"instance",icon:"🧱",labelKey:"changelog.category.instance"},{key:"property",icon:"🎨",labelKey:"changelog.category.property"},{key:"lighting",icon:"🌅",labelKey:"changelog.category.lighting"},{key:"terrain",icon:"⛰️",labelKey:"changelog.category.terrain"},{key:"asset",icon:"📦",labelKey:"changelog.category.asset"}];function A(t){if(!t)return"--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}`}function Le(t){if(!t)return"--:--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}:${String(s.getSeconds()).padStart(2,"0")}`}function Ae(t,s){if(!t||!s)return"";const l=new Date(s).getTime()-new Date(t).getTime();return l<0?"":`${Math.round(l/6e4)}min`}function Ke(t){switch(t){case"exact":return n.confidenceExact;case"partial":return n.confidencePartial;case"after-only":return n.confidenceAfterOnly;case"intent-only":return n.confidenceIntentOnly;default:return n.confidenceUnknown}}function Re(t,s){switch(s){case"exact":return t("changelog.detail.confidence.exact","Exact");case"partial":return t("changelog.detail.confidence.partial","Partial");case"after-only":return t("changelog.detail.confidence.afterOnly","After only");case"intent-only":return t("changelog.detail.confidence.intentOnly","Intent only");default:return t("changelog.detail.confidence.unknown","Unknown")}}function $e(t,s){switch(s){case"exact":return t("changelog.detail.confidence.exact.tooltip","Both the before and after state were confirmed for this change.");case"partial":return t("changelog.detail.confidence.partial.tooltip","Only part of the before and after state could be confirmed for this change.");case"after-only":return t("changelog.detail.confidence.afterOnly.tooltip","Only the resulting state after the change could be confirmed.");case"intent-only":return t("changelog.detail.confidence.intentOnly.tooltip","Only the requested action was recorded, not the resulting state.");default:return t("changelog.detail.confidence.unknown.tooltip","This change could not be confidently classified from the available data.")}}function Fe(){var f,x,p,j,_,b,v,S,C,N,T,g,k,h;const{t}=M(),{id:s}=B(),l=D(),a=U(s),[d,u]=r.useState("all"),[q,w]=r.useState(null),y=r.useMemo(()=>[...d==="all"?a.changes:a.changes.filter(c=>c.category===d)].reverse(),[a.changes,d]);if(a.loading)return e.jsx("div",{className:n.loading,children:t("common.loading","Loading...")});if(a.error)return e.jsxs("div",{className:n.error,children:[a.error,e.jsx("br",{}),e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const E=Ae(a.startTime,a.endTime),I=a.endTime?`${A(a.startTime)} → ${A(a.endTime)} (${E})`:`${A(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,O=!!((f=a.contextSummary)!=null&&f.intent||(x=a.contextSummary)!=null&&x.testScenario||(p=a.contextSummary)!=null&&p.expectedBehavior||(j=a.contextSummary)!=null&&j.observedBehavior),L=!!((_=a.verificationSummary)!=null&&_.label||(b=a.verificationSummary)!=null&&b.status||(v=a.verificationSummary)!=null&&v.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:I}),e.jsx(m,{text:a.status==="active"?t("changelog.card.active.tooltip","This session is still receiving new game changes."):t("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:a.status==="active"?n.statusActive:n.statusCompleted,children:a.status==="active"?t("changelog.card.active","Active"):t("changelog.card.completed","Completed")})})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:t("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:n.summaryGrid,children:$.map(i=>{const c=a.changeSummary;let o;switch(i.key){case"script":o=c.scriptsModified+c.scriptsCreated;break;case"instance":o=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":o=c.propertiesChanged;break;case"lighting":o=c.lightingChanged?1:0;break;case"terrain":o=c.terrainChanged?1:0;break;case"asset":o=c.assetsInserted;break;default:o=0}const K=d===i.key;return e.jsxs("div",{className:`${n.summaryCard} ${K?n.summaryCardActive:""}`,onClick:()=>u(K?"all":i.key),children:[e.jsx("span",{className:n.summaryIcon,children:i.icon}),e.jsx("div",{className:n.summaryCount,children:o}),e.jsx("div",{className:n.summaryLabel,children:t(i.labelKey,i.key)})]},i.key)})})]}),O&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:t("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:n.contextGrid,children:[((S=a.contextSummary)==null?void 0:S.intent)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.intent})]}),((C=a.contextSummary)==null?void 0:C.testScenario)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.why","Why this test ran")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.testScenario})]}),((N=a.contextSummary)==null?void 0:N.expectedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.expected","Expected")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.expectedBehavior})]}),((T=a.contextSummary)==null?void 0:T.observedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.observed","Observed")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.observedBehavior})]})]})]}),L&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:t("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:n.contextGrid,children:[((g=a.verificationSummary)==null?void 0:g.label)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.label","Result")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.label})]}),((k=a.verificationSummary)==null?void 0:k.status)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.status","Status")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.status})]}),((h=a.verificationSummary)==null?void 0:h.testTimestamp)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:t("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:n.timelineFilter,children:[e.jsx("span",{className:n.filterLabel,children:e.jsx(V,{label:`${t("changelog.detail.filterCategory","Category")}:`,tooltip:t("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:n.filterSelect,value:d,onChange:i=>u(i.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),$.map(i=>e.jsxs("option",{value:i.key,children:[i.icon," ",t(i.labelKey,i.key)]},i.key))]})]}),y.length===0?e.jsx("div",{className:n.empty,children:t("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:n.timeline,children:y.map((i,c)=>{const o=q===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>w(o?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Le(i.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:H(i.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[i.summary,e.jsx(m,{text:$e(t,i.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Ke(i.confidence)}`,children:Re(t,i.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:i.target})]})]}),o&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(Me,{change:i})})]},c)})})]})]})}function Me({change:t}){return t.category==="script"&&(t.before||t.after)?e.jsx(F,{before:t.before,after:t.after}):t.category==="property"?e.jsx(G,{before:t.before,after:t.after}):t.details?e.jsx("pre",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-secondary)",margin:0,whiteSpace:"pre-wrap",wordBreak:"break-all"},children:JSON.stringify(t.details,null,2)}):e.jsx("div",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-muted)"},children:t.target})}export{Fe as Component};
|
|
1
|
+
import{r,a as R,u as M,b as B,c as D,j as e,T as m}from"./index-OH9mpHwW.js";import{I as V}from"./InfoLabel-CLvjiyTG.js";import{D as F,P as G}from"./PropertyDiff-BnOZxkTS.js";function P(t){const s={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const l of t)switch(l.category){case"script":l.changeType==="create"?s.scriptsCreated++:s.scriptsModified++;break;case"instance":l.changeType==="create"?s.instancesCreated++:l.changeType==="delete"?s.instancesDeleted++:l.changeType==="move"&&s.instancesMoved++;break;case"property":s.propertiesChanged++;break;case"lighting":s.lightingChanged=!0;break;case"terrain":s.terrainChanged=!0;break;case"asset":s.assetsInserted++;break}return s}function U(t){const[s,l]=r.useState(""),[a,d]=r.useState(""),[u,q]=r.useState(),[w,y]=r.useState("completed"),[E,I]=r.useState([]),[O,L]=r.useState([]),[f,x]=r.useState([]),[p,j]=r.useState(),[_,b]=r.useState(),[v,S]=r.useState(),[C,N]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[T,g]=r.useState(!0),[k,h]=r.useState(null),i=r.useCallback(async()=>{if(t){g(!0),h(null);try{const[c,o]=await Promise.all([R.get(`/api/dashboard/changelog/${t}`),R.get(`/api/dashboard/changelog/${t}/changes`)]);l(c.entryId),d(c.startTime),q(c.endTime),y(c.status),I(c.entries),L(c.failures),j(c.contextSummary),b(c.replayMetadata),S(c.verificationSummary),x(o.changes),N(P(o.changes))}catch(c){h(c instanceof Error?c.message:"Failed to load changelog detail")}finally{g(!1)}}},[t]);return r.useEffect(()=>{i()},[i]),{entryId:s,startTime:a,endTime:u,status:w,entries:E,failures:O,changes:f,changeSummary:C,contextSummary:p,replayMetadata:_,verificationSummary:v,loading:T,error:k,refresh:i}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function H(t){return z[t]??"❓"}const J="_page_q2jbi_2",W="_header_q2jbi_10",Y="_backLink_q2jbi_16",Q="_headerTitle_q2jbi_29",X="_headerTime_q2jbi_37",Z="_statusActive_q2jbi_44",ee="_statusCompleted_q2jbi_49",te="_section_q2jbi_54",ne="_sectionTitle_q2jbi_61",ae="_summaryGrid_q2jbi_74",ie="_summaryCard_q2jbi_80",se="_summaryCardActive_q2jbi_94",ce="_summaryIcon_q2jbi_99",re="_summaryCount_q2jbi_105",oe="_summaryLabel_q2jbi_112",le="_contextGrid_q2jbi_121",de="_contextRow_q2jbi_127",me="_contextKey_q2jbi_133",ge="_contextValue_q2jbi_141",he="_timelineFilter_q2jbi_149",ue="_filterLabel_q2jbi_156",ye="_filterSelect_q2jbi_162",fe="_timeline_q2jbi_149",xe="_timelineEntry_q2jbi_182",pe="_timelineTime_q2jbi_199",je="_timelineIcon_q2jbi_207",_e="_timelineBody_q2jbi_212",be="_timelineSummary_q2jbi_217",ve="_timelineTarget_q2jbi_224",Se="_timelineConfidence_q2jbi_231",Ce="_confidenceExact_q2jbi_240",Ne="_confidencePartial_q2jbi_245",Te="_confidenceAfterOnly_q2jbi_250",ke="_confidenceIntentOnly_q2jbi_255",qe="_confidenceUnknown_q2jbi_260",we="_timelineExpanded_q2jbi_266",Ee="_empty_q2jbi_338",Ie="_loading_q2jbi_347",Oe="_error_q2jbi_356",n={page:J,header:W,backLink:Y,headerTitle:Q,headerTime:X,statusActive:Z,statusCompleted:ee,section:te,sectionTitle:ne,summaryGrid:ae,summaryCard:ie,summaryCardActive:se,summaryIcon:ce,summaryCount:re,summaryLabel:oe,contextGrid:le,contextRow:de,contextKey:me,contextValue:ge,timelineFilter:he,filterLabel:ue,filterSelect:ye,timeline:fe,timelineEntry:xe,timelineTime:pe,timelineIcon:je,timelineBody:_e,timelineSummary:be,timelineTarget:ve,timelineConfidence:Se,confidenceExact:Ce,confidencePartial:Ne,confidenceAfterOnly:Te,confidenceIntentOnly:ke,confidenceUnknown:qe,timelineExpanded:we,empty:Ee,loading:Ie,error:Oe},$=[{key:"script",icon:"📝",labelKey:"changelog.category.script"},{key:"instance",icon:"🧱",labelKey:"changelog.category.instance"},{key:"property",icon:"🎨",labelKey:"changelog.category.property"},{key:"lighting",icon:"🌅",labelKey:"changelog.category.lighting"},{key:"terrain",icon:"⛰️",labelKey:"changelog.category.terrain"},{key:"asset",icon:"📦",labelKey:"changelog.category.asset"}];function A(t){if(!t)return"--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}`}function Le(t){if(!t)return"--:--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}:${String(s.getSeconds()).padStart(2,"0")}`}function Ae(t,s){if(!t||!s)return"";const l=new Date(s).getTime()-new Date(t).getTime();return l<0?"":`${Math.round(l/6e4)}min`}function Ke(t){switch(t){case"exact":return n.confidenceExact;case"partial":return n.confidencePartial;case"after-only":return n.confidenceAfterOnly;case"intent-only":return n.confidenceIntentOnly;default:return n.confidenceUnknown}}function Re(t,s){switch(s){case"exact":return t("changelog.detail.confidence.exact","Exact");case"partial":return t("changelog.detail.confidence.partial","Partial");case"after-only":return t("changelog.detail.confidence.afterOnly","After only");case"intent-only":return t("changelog.detail.confidence.intentOnly","Intent only");default:return t("changelog.detail.confidence.unknown","Unknown")}}function $e(t,s){switch(s){case"exact":return t("changelog.detail.confidence.exact.tooltip","Both the before and after state were confirmed for this change.");case"partial":return t("changelog.detail.confidence.partial.tooltip","Only part of the before and after state could be confirmed for this change.");case"after-only":return t("changelog.detail.confidence.afterOnly.tooltip","Only the resulting state after the change could be confirmed.");case"intent-only":return t("changelog.detail.confidence.intentOnly.tooltip","Only the requested action was recorded, not the resulting state.");default:return t("changelog.detail.confidence.unknown.tooltip","This change could not be confidently classified from the available data.")}}function Fe(){var f,x,p,j,_,b,v,S,C,N,T,g,k,h;const{t}=M(),{id:s}=B(),l=D(),a=U(s),[d,u]=r.useState("all"),[q,w]=r.useState(null),y=r.useMemo(()=>[...d==="all"?a.changes:a.changes.filter(c=>c.category===d)].reverse(),[a.changes,d]);if(a.loading)return e.jsx("div",{className:n.loading,children:t("common.loading","Loading...")});if(a.error)return e.jsxs("div",{className:n.error,children:[a.error,e.jsx("br",{}),e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const E=Ae(a.startTime,a.endTime),I=a.endTime?`${A(a.startTime)} → ${A(a.endTime)} (${E})`:`${A(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,O=!!((f=a.contextSummary)!=null&&f.intent||(x=a.contextSummary)!=null&&x.testScenario||(p=a.contextSummary)!=null&&p.expectedBehavior||(j=a.contextSummary)!=null&&j.observedBehavior),L=!!((_=a.verificationSummary)!=null&&_.label||(b=a.verificationSummary)!=null&&b.status||(v=a.verificationSummary)!=null&&v.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:I}),e.jsx(m,{text:a.status==="active"?t("changelog.card.active.tooltip","This session is still receiving new game changes."):t("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:a.status==="active"?n.statusActive:n.statusCompleted,children:a.status==="active"?t("changelog.card.active","Active"):t("changelog.card.completed","Completed")})})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:t("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:n.summaryGrid,children:$.map(i=>{const c=a.changeSummary;let o;switch(i.key){case"script":o=c.scriptsModified+c.scriptsCreated;break;case"instance":o=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":o=c.propertiesChanged;break;case"lighting":o=c.lightingChanged?1:0;break;case"terrain":o=c.terrainChanged?1:0;break;case"asset":o=c.assetsInserted;break;default:o=0}const K=d===i.key;return e.jsxs("div",{className:`${n.summaryCard} ${K?n.summaryCardActive:""}`,onClick:()=>u(K?"all":i.key),children:[e.jsx("span",{className:n.summaryIcon,children:i.icon}),e.jsx("div",{className:n.summaryCount,children:o}),e.jsx("div",{className:n.summaryLabel,children:t(i.labelKey,i.key)})]},i.key)})})]}),O&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:t("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:n.contextGrid,children:[((S=a.contextSummary)==null?void 0:S.intent)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.intent})]}),((C=a.contextSummary)==null?void 0:C.testScenario)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.why","Why this test ran")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.testScenario})]}),((N=a.contextSummary)==null?void 0:N.expectedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.expected","Expected")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.expectedBehavior})]}),((T=a.contextSummary)==null?void 0:T.observedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.observed","Observed")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.observedBehavior})]})]})]}),L&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:t("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:n.contextGrid,children:[((g=a.verificationSummary)==null?void 0:g.label)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.label","Result")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.label})]}),((k=a.verificationSummary)==null?void 0:k.status)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.status","Status")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.status})]}),((h=a.verificationSummary)==null?void 0:h.testTimestamp)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{text:t("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:t("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:n.timelineFilter,children:[e.jsx("span",{className:n.filterLabel,children:e.jsx(V,{label:`${t("changelog.detail.filterCategory","Category")}:`,tooltip:t("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:n.filterSelect,value:d,onChange:i=>u(i.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),$.map(i=>e.jsxs("option",{value:i.key,children:[i.icon," ",t(i.labelKey,i.key)]},i.key))]})]}),y.length===0?e.jsx("div",{className:n.empty,children:t("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:n.timeline,children:y.map((i,c)=>{const o=q===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>w(o?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Le(i.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:H(i.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[i.summary,e.jsx(m,{text:$e(t,i.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Ke(i.confidence)}`,children:Re(t,i.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:i.target})]})]}),o&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(Me,{change:i})})]},c)})})]})]})}function Me({change:t}){return t.category==="script"&&(t.before||t.after)?e.jsx(F,{before:t.before,after:t.after}):t.category==="property"?e.jsx(G,{before:t.before,after:t.after}):t.details?e.jsx("pre",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-secondary)",margin:0,whiteSpace:"pre-wrap",wordBreak:"break-all"},children:JSON.stringify(t.details,null,2)}):e.jsx("div",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-muted)"},children:t.target})}export{Fe as Component};
|