@weppy/roblox-mcp 2.2.1 → 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 +25 -0
- package/README.md +4 -7
- package/docs/en/installation/README.md +3 -4
- package/docs/es/README.md +2 -5
- package/docs/es/installation/README.md +3 -4
- package/docs/id/README.md +1 -4
- package/docs/id/installation/README.md +3 -4
- 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 +1 -4
- package/docs/ja/installation/README.md +2 -3
- package/docs/ko/README.md +4 -7
- package/docs/ko/installation/README.md +3 -4
- package/docs/pt-br/README.md +2 -5
- package/docs/pt-br/installation/README.md +3 -4
- package/install.ps1 +495 -8
- package/install.sh +499 -9
- 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
|
@@ -16,7 +16,7 @@ AIアプリが「青いパーツを作って」と言うと、MCPサーバーが
|
|
|
16
16
|
|
|
17
17
|
## ワンラインインストール(推奨)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
1つのコマンドで導入できます:
|
|
20
20
|
|
|
21
21
|
**macOS / Linux**
|
|
22
22
|
|
|
@@ -32,8 +32,7 @@ irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1
|
|
|
32
32
|
|
|
33
33
|
Roblox Studioを再起動したら完了です!
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
**Codex App** と **Antigravity** はスクリプト完了後に手動設定が必要です。
|
|
35
|
+
自動MCP登録は **Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity** に対応しています。
|
|
37
36
|
|
|
38
37
|
WindowsでPowerShellの実行がブロックされる場合は、下の手動インストールに進んでください。ZIPパッケージを使う場合は `setup-plugin.bat` と `setup-mcp.bat` を実行できます。
|
|
39
38
|
|
package/docs/ko/README.md
CHANGED
|
@@ -18,8 +18,6 @@ Claude, Codex, Gemini 같은 AI 코딩 에이전트는 강력하지만 — Roblo
|
|
|
18
18
|
|
|
19
19
|
## 빠른 설치
|
|
20
20
|
|
|
21
|
-
**원라인 설치** — MCP 서버, Roblox Studio 플러그인, AI 앱 등록을 한 번에 진행합니다:
|
|
22
|
-
|
|
23
21
|
**macOS / Linux**
|
|
24
22
|
|
|
25
23
|
```bash
|
|
@@ -32,16 +30,15 @@ curl -fsSL https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/inst
|
|
|
32
30
|
irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1 | iex
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
Roblox Studio를
|
|
33
|
+
AI 앱을 다시 열고 Roblox Studio를 재시작하세요.
|
|
36
34
|
|
|
37
|
-
자동 MCP 등록은
|
|
38
|
-
**Codex App**과 **Antigravity**는 스크립트 완료 후 수동 설정이 필요합니다.
|
|
35
|
+
자동 MCP 등록은 **Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity**를 지원합니다.
|
|
39
36
|
|
|
40
|
-
Windows에서 PowerShell 실행이 차단되면 아래
|
|
37
|
+
Windows에서 PowerShell 실행이 차단되면 아래 설치 가이드를 사용하세요. ZIP 패키지를 사용하는 경우 `setup-plugin.bat`, `setup-mcp.bat`도 사용할 수 있습니다.
|
|
41
38
|
|
|
42
39
|
### 수동 설치
|
|
43
40
|
|
|
44
|
-
원라인 설치가 동작하지 않거나 환경상 자동 설치를 사용할 수 없는 경우, 아래
|
|
41
|
+
원라인 설치가 동작하지 않거나 환경상 자동 설치를 사용할 수 없는 경우, 아래 설치 가이드를 대안으로 진행하세요.
|
|
45
42
|
|
|
46
43
|
**1단계** — Roblox Studio 플러그인 설치 (Studio와 AI를 연결하는 다리):
|
|
47
44
|
[플러그인 설치 가이드](installation/roblox-plugin.md)
|
|
@@ -16,7 +16,7 @@ AI 앱이 "파란 파트를 만들어줘"라고 하면, MCP 서버가 이 요청
|
|
|
16
16
|
|
|
17
17
|
## 원라인 설치 (권장)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
아래 명령어 한 줄로 MCP 서버와 플러그인을 한 번에 설치합니다:
|
|
20
20
|
|
|
21
21
|
**macOS / Linux**
|
|
22
22
|
|
|
@@ -30,12 +30,11 @@ curl -fsSL https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/inst
|
|
|
30
30
|
irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1 | iex
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Roblox Studio를
|
|
33
|
+
AI 앱을 다시 열고 Roblox Studio를 재시작하세요.
|
|
34
34
|
|
|
35
35
|
설치 중 오류가 발생하면 임시 로그 파일 경로를 출력하고, 대화형 실행에서는 종료 전에 콘솔을 유지해서 원인을 확인할 수 있습니다.
|
|
36
36
|
|
|
37
|
-
자동 MCP 등록은
|
|
38
|
-
**Codex App**과 **Antigravity**는 스크립트 완료 후 수동 설정이 필요합니다.
|
|
37
|
+
자동 MCP 등록은 **Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity**를 지원합니다.
|
|
39
38
|
|
|
40
39
|
Windows에서 PowerShell 실행이 차단되면 아래 수동 설치로 진행하세요. ZIP 패키지를 사용하는 경우 `setup-plugin.bat`, `setup-mcp.bat`를 실행할 수 있습니다.
|
|
41
40
|
|
package/docs/pt-br/README.md
CHANGED
|
@@ -18,8 +18,6 @@ Sem necessidade de copiar e colar código. A IA trabalha e você confere os resu
|
|
|
18
18
|
|
|
19
19
|
## Instalacao rapida
|
|
20
20
|
|
|
21
|
-
**Instalacao em um comando** — Instala o servidor MCP, o plugin do Roblox Studio e registra nos apps de IA em um único passo:
|
|
22
|
-
|
|
23
21
|
**macOS / Linux**
|
|
24
22
|
|
|
25
23
|
```bash
|
|
@@ -34,14 +32,13 @@ irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1
|
|
|
34
32
|
|
|
35
33
|
Reinicie o Roblox Studio — pronto!
|
|
36
34
|
|
|
37
|
-
O registro automático de MCP
|
|
38
|
-
**Codex App** e **Antigravity** ainda exigem configuração manual depois que o script terminar.
|
|
35
|
+
O registro automático de MCP suporta **Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI e Antigravity**.
|
|
39
36
|
|
|
40
37
|
Se a execução do PowerShell estiver bloqueada no Windows, siga a instalação manual abaixo. Se estiver usando o pacote ZIP, você também pode usar `setup-plugin.bat` e `setup-mcp.bat`.
|
|
41
38
|
|
|
42
39
|
### Instalacao manual
|
|
43
40
|
|
|
44
|
-
Se a
|
|
41
|
+
Se a instalacao em um comando nao funcionar, ou se a instalacao automatica nao puder ser usada no seu ambiente, use a instalacao manual abaixo como alternativa.
|
|
45
42
|
|
|
46
43
|
**Passo 1** — Instale o plugin do Roblox Studio (ponte entre Studio e IA):
|
|
47
44
|
[Guia de instalacao do plugin](installation/roblox-plugin.md)
|
|
@@ -16,7 +16,7 @@ Quando o app de IA diz "cria uma parte azul", o servidor MCP converte o pedido e
|
|
|
16
16
|
|
|
17
17
|
## Instalação em um comando (Recomendado)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Instale tudo com um único comando:
|
|
20
20
|
|
|
21
21
|
**macOS / Linux**
|
|
22
22
|
|
|
@@ -32,8 +32,7 @@ irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1
|
|
|
32
32
|
|
|
33
33
|
Reinicie o Roblox Studio — pronto!
|
|
34
34
|
|
|
35
|
-
O registro automático de MCP
|
|
36
|
-
**Codex App** e **Antigravity** ainda exigem configuração manual depois que o script terminar.
|
|
35
|
+
O registro automático de MCP suporta **Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI e Antigravity**.
|
|
37
36
|
|
|
38
37
|
Se a execução do PowerShell estiver bloqueada no Windows, siga a instalação manual abaixo. Se estiver usando o pacote ZIP, você também pode executar `setup-plugin.bat` e `setup-mcp.bat`.
|
|
39
38
|
|
|
@@ -41,7 +40,7 @@ Se a execução do PowerShell estiver bloqueada no Windows, siga a instalação
|
|
|
41
40
|
|
|
42
41
|
## Instalação manual
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
Se a instalacao em um comando nao funcionar, ou quando a instalacao automatica nao puder ser usada no seu ambiente, use a instalacao manual abaixo como alternativa.
|
|
45
44
|
|
|
46
45
|
### Passo 1: Instalar plugin do Roblox Studio
|
|
47
46
|
|
package/install.ps1
CHANGED
|
@@ -139,12 +139,475 @@ function Test-McpJsonConfigured($configPath) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
# Antigravity 설정에 canonical mcpServers 래퍼로 MCP 서버를 추가하고 legacy flat key를 정리
|
|
143
|
+
function Add-AntigravityMcpConfig($configPath) {
|
|
144
|
+
$parentDir = Split-Path $configPath -Parent
|
|
145
|
+
if (-not (Test-Path $parentDir)) { New-Item -ItemType Directory -Path $parentDir -Force | Out-Null }
|
|
146
|
+
$env:MCP_CONFIG_PATH = $configPath
|
|
147
|
+
try {
|
|
148
|
+
node -e @"
|
|
149
|
+
const fs = require('fs');
|
|
150
|
+
const configPath = process.env.MCP_CONFIG_PATH;
|
|
151
|
+
let config = {};
|
|
152
|
+
try { config = JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch {}
|
|
153
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
154
|
+
config = {};
|
|
155
|
+
}
|
|
156
|
+
const mcpServers = config.mcpServers;
|
|
157
|
+
if (mcpServers !== undefined && (typeof mcpServers !== 'object' || mcpServers === null || Array.isArray(mcpServers))) {
|
|
158
|
+
throw new Error('Antigravity mcpServers must be an object');
|
|
159
|
+
}
|
|
160
|
+
const next = { ...config };
|
|
161
|
+
delete next['weppy-roblox-mcp'];
|
|
162
|
+
next.mcpServers = {
|
|
163
|
+
...(mcpServers || {}),
|
|
164
|
+
'weppy-roblox-mcp': { command: 'npx', args: ['-y', '@weppy/roblox-mcp'] }
|
|
165
|
+
};
|
|
166
|
+
config = next;
|
|
167
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
168
|
+
"@
|
|
169
|
+
} finally {
|
|
170
|
+
Remove-Item Env:\MCP_CONFIG_PATH -ErrorAction SilentlyContinue
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function Test-AntigravityMcpConfigured($configPath) {
|
|
175
|
+
if (-not (Test-Path $configPath)) {
|
|
176
|
+
return $false
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
$config = Get-Content -Path $configPath -Raw | ConvertFrom-Json
|
|
181
|
+
$hasLegacyFlatKey = $config.PSObject.Properties.Name -contains 'weppy-roblox-mcp'
|
|
182
|
+
$server = $config.mcpServers.'weppy-roblox-mcp'
|
|
183
|
+
$hasCanonicalArgs = ($server.args -is [System.Array]) -and ($server.args.Count -eq 2) -and ($server.args[0] -eq '-y') -and ($server.args[1] -eq '@weppy/roblox-mcp')
|
|
184
|
+
return ($server.command -eq 'npx') -and $hasCanonicalArgs -and (-not $hasLegacyFlatKey)
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return $false
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
142
191
|
function Test-CodexConfigConfigured($configPath) {
|
|
143
192
|
if (-not (Test-Path $configPath)) {
|
|
144
193
|
return $false
|
|
145
194
|
}
|
|
146
195
|
|
|
147
|
-
|
|
196
|
+
$env:MCP_CODEX_CONFIG_PATH = $configPath
|
|
197
|
+
try {
|
|
198
|
+
node -e @"
|
|
199
|
+
const fs = require('fs');
|
|
200
|
+
|
|
201
|
+
const configPath = process.env.MCP_CODEX_CONFIG_PATH;
|
|
202
|
+
const serverName = 'weppy-roblox-mcp';
|
|
203
|
+
const expectedCommand = 'npx';
|
|
204
|
+
const expectedArgs = ['-y', '@weppy/roblox-mcp'];
|
|
205
|
+
const headerPattern = new RegExp(
|
|
206
|
+
'^\\s*\\[\\s*mcp_servers\\.' + serverName.replace(/[.*+?^${}()|[\]\\\\]/g, '\\$&') + '\\s*\\]\\s*(?:#.*)?$'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
function stripCommentOutsideStrings(line) {
|
|
210
|
+
let inSingle = false;
|
|
211
|
+
let inDouble = false;
|
|
212
|
+
let escaped = false;
|
|
213
|
+
|
|
214
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
215
|
+
const char = line[index];
|
|
216
|
+
|
|
217
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
218
|
+
inDouble = !inDouble;
|
|
219
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
220
|
+
inSingle = !inSingle;
|
|
221
|
+
} else if (char === '#' && !inSingle && !inDouble) {
|
|
222
|
+
return line.slice(0, index).trimEnd();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
escaped = char === '\\' && !escaped;
|
|
226
|
+
if (char !== '\\') {
|
|
227
|
+
escaped = false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return line.trimEnd();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function countTripleQuoteToggles(line, quote) {
|
|
235
|
+
let count = 0;
|
|
236
|
+
let inSingle = false;
|
|
237
|
+
let inDouble = false;
|
|
238
|
+
let escaped = false;
|
|
239
|
+
|
|
240
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
241
|
+
const char = line[index] ?? '';
|
|
242
|
+
const nextThree = line.slice(index, index + 3);
|
|
243
|
+
const isOutsideStrings = !inSingle && !inDouble;
|
|
244
|
+
|
|
245
|
+
if (isOutsideStrings && nextThree === quote.repeat(3)) {
|
|
246
|
+
count += 1;
|
|
247
|
+
index += 2;
|
|
248
|
+
escaped = false;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
253
|
+
inDouble = !inDouble;
|
|
254
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
255
|
+
inSingle = !inSingle;
|
|
256
|
+
} else if (char === '#' && !inSingle && !inDouble) {
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
escaped = char === '\\' && !escaped;
|
|
261
|
+
if (char !== '\\') {
|
|
262
|
+
escaped = false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return count;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function advanceTripleQuoteState(line, state) {
|
|
270
|
+
const next = { ...state };
|
|
271
|
+
const tripleDoubleCount = countTripleQuoteToggles(line, '"');
|
|
272
|
+
const tripleSingleCount = countTripleQuoteToggles(line, "'");
|
|
273
|
+
|
|
274
|
+
if (!next.inTripleSingle && tripleDoubleCount % 2 === 1) {
|
|
275
|
+
next.inTripleDouble = !next.inTripleDouble;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!next.inTripleDouble && tripleSingleCount % 2 === 1) {
|
|
279
|
+
next.inTripleSingle = !next.inTripleSingle;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return next;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function isTomlTableHeaderLine(line) {
|
|
286
|
+
const normalized = stripCommentOutsideStrings(line).trim();
|
|
287
|
+
|
|
288
|
+
if (normalized.length === 0) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return /^\[\[.*\]\]$/.test(normalized) || /^\[.*\]$/.test(normalized);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function findAllCodexBlocks(source) {
|
|
296
|
+
const lines = source.split('\n');
|
|
297
|
+
const blocks = [];
|
|
298
|
+
let activeLines = null;
|
|
299
|
+
let state = {
|
|
300
|
+
inTripleDouble: false,
|
|
301
|
+
inTripleSingle: false,
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
for (const line of lines) {
|
|
305
|
+
const isHeaderCandidate = !state.inTripleDouble && !state.inTripleSingle && isTomlTableHeaderLine(line);
|
|
306
|
+
const isCodexHeader = isHeaderCandidate && headerPattern.test(line);
|
|
307
|
+
|
|
308
|
+
if (isCodexHeader) {
|
|
309
|
+
if (activeLines !== null) {
|
|
310
|
+
blocks.push(activeLines.join('\n').trim());
|
|
311
|
+
}
|
|
312
|
+
activeLines = [line];
|
|
313
|
+
} else if (activeLines !== null && isHeaderCandidate) {
|
|
314
|
+
blocks.push(activeLines.join('\n').trim());
|
|
315
|
+
activeLines = null;
|
|
316
|
+
} else if (activeLines !== null) {
|
|
317
|
+
activeLines.push(line);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
state = advanceTripleQuoteState(line, state);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (activeLines !== null) {
|
|
324
|
+
blocks.push(activeLines.join('\n').trim());
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return blocks;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function parseStringAssignment(value, key) {
|
|
331
|
+
const match = new RegExp('^\\s*' + key + '\\s*=\\s*(["\\'])([^"\\']+)\\1\\s*$').exec(value);
|
|
332
|
+
return match ? match[2] : null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function parseTomlStringArray(value) {
|
|
336
|
+
const match = /^\s*args\s*=\s*\[(.*)\]\s*$/ms.exec(value.trim());
|
|
337
|
+
|
|
338
|
+
if (match === null) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const body = match[1] ?? '';
|
|
343
|
+
const values = [];
|
|
344
|
+
let cursor = 0;
|
|
345
|
+
let expectValue = true;
|
|
346
|
+
|
|
347
|
+
while (cursor < body.length) {
|
|
348
|
+
while (cursor < body.length && /\s/.test(body[cursor] ?? '')) {
|
|
349
|
+
cursor += 1;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (cursor >= body.length) {
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (!expectValue) {
|
|
357
|
+
if (body[cursor] !== ',') {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
cursor += 1;
|
|
361
|
+
expectValue = true;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const quote = body[cursor];
|
|
366
|
+
if (quote !== '"' && quote !== "'") {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
cursor += 1;
|
|
371
|
+
let token = '';
|
|
372
|
+
let escaped = false;
|
|
373
|
+
|
|
374
|
+
while (cursor < body.length) {
|
|
375
|
+
const char = body[cursor] ?? '';
|
|
376
|
+
|
|
377
|
+
if (char === quote && !escaped) {
|
|
378
|
+
cursor += 1;
|
|
379
|
+
values.push(token);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
token += char;
|
|
384
|
+
escaped = char === '\\' && !escaped;
|
|
385
|
+
if (char !== '\\') {
|
|
386
|
+
escaped = false;
|
|
387
|
+
}
|
|
388
|
+
cursor += 1;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (cursor > body.length) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
expectValue = false;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const leftover = body.slice(cursor).trim();
|
|
399
|
+
if (leftover === ',') {
|
|
400
|
+
return values;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return leftover.length === 0 ? values : null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function collectArrayLines(lines, startIndex) {
|
|
407
|
+
const collected = [stripCommentOutsideStrings(lines[startIndex] ?? '')];
|
|
408
|
+
let bracketDepth = 0;
|
|
409
|
+
let inSingle = false;
|
|
410
|
+
let inDouble = false;
|
|
411
|
+
let escaped = false;
|
|
412
|
+
|
|
413
|
+
for (let lineIndex = startIndex; lineIndex < lines.length; lineIndex += 1) {
|
|
414
|
+
const sanitized = stripCommentOutsideStrings(lines[lineIndex] ?? '');
|
|
415
|
+
if (lineIndex !== startIndex) {
|
|
416
|
+
collected.push(sanitized);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
for (let index = 0; index < sanitized.length; index += 1) {
|
|
420
|
+
const char = sanitized[index] ?? '';
|
|
421
|
+
|
|
422
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
423
|
+
inDouble = !inDouble;
|
|
424
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
425
|
+
inSingle = !inSingle;
|
|
426
|
+
} else if (!inSingle && !inDouble) {
|
|
427
|
+
if (char === '[') {
|
|
428
|
+
bracketDepth += 1;
|
|
429
|
+
} else if (char === ']') {
|
|
430
|
+
bracketDepth -= 1;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
escaped = char === '\\' && !escaped;
|
|
435
|
+
if (char !== '\\') {
|
|
436
|
+
escaped = false;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (bracketDepth <= 0) {
|
|
441
|
+
return {
|
|
442
|
+
nextIndex: lineIndex,
|
|
443
|
+
text: collected.join('\n'),
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function parseCodexBlock(blockContent) {
|
|
452
|
+
const lines = blockContent.split('\n');
|
|
453
|
+
let command = null;
|
|
454
|
+
let args = null;
|
|
455
|
+
let hasConflict = false;
|
|
456
|
+
let inTripleDouble = false;
|
|
457
|
+
let inTripleSingle = false;
|
|
458
|
+
|
|
459
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
460
|
+
const line = lines[index] ?? '';
|
|
461
|
+
const sanitized = stripCommentOutsideStrings(line);
|
|
462
|
+
const trimmed = sanitized.trim();
|
|
463
|
+
|
|
464
|
+
if (inTripleDouble) {
|
|
465
|
+
if (countTripleQuoteToggles(sanitized, '"') % 2 === 1) {
|
|
466
|
+
inTripleDouble = false;
|
|
467
|
+
}
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (inTripleSingle) {
|
|
472
|
+
if (countTripleQuoteToggles(sanitized, "'") % 2 === 1) {
|
|
473
|
+
inTripleSingle = false;
|
|
474
|
+
}
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (countTripleQuoteToggles(sanitized, '"') % 2 === 1) {
|
|
479
|
+
inTripleDouble = true;
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (countTripleQuoteToggles(sanitized, "'") % 2 === 1) {
|
|
484
|
+
inTripleSingle = true;
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (trimmed.length === 0) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (/^command\s*=/.test(trimmed)) {
|
|
493
|
+
const parsedCommand = parseStringAssignment(trimmed, 'command');
|
|
494
|
+
if (command !== null || parsedCommand === null) {
|
|
495
|
+
hasConflict = true;
|
|
496
|
+
} else {
|
|
497
|
+
command = parsedCommand;
|
|
498
|
+
}
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (/^args\s*=/.test(trimmed)) {
|
|
503
|
+
const collected = collectArrayLines(lines, index);
|
|
504
|
+
const parsedArgs = collected === null ? null : parseTomlStringArray(collected.text);
|
|
505
|
+
|
|
506
|
+
if (args !== null || parsedArgs === null || collected === null) {
|
|
507
|
+
hasConflict = true;
|
|
508
|
+
} else {
|
|
509
|
+
args = parsedArgs;
|
|
510
|
+
index = collected.nextIndex;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
args,
|
|
517
|
+
command,
|
|
518
|
+
hasConflict,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function isStructurallySafe(source) {
|
|
523
|
+
let bracketDepth = 0;
|
|
524
|
+
let braceDepth = 0;
|
|
525
|
+
let inSingle = false;
|
|
526
|
+
let inDouble = false;
|
|
527
|
+
let escaped = false;
|
|
528
|
+
let tripleState = {
|
|
529
|
+
inTripleDouble: false,
|
|
530
|
+
inTripleSingle: false,
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
for (const line of source.split('\n')) {
|
|
534
|
+
tripleState = advanceTripleQuoteState(line, tripleState);
|
|
535
|
+
|
|
536
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
537
|
+
const char = line[index] ?? '';
|
|
538
|
+
|
|
539
|
+
if (!inSingle && !inDouble && char === '#') {
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (char === '"' && !inSingle && !escaped) {
|
|
544
|
+
inDouble = !inDouble;
|
|
545
|
+
} else if (char === "'" && !inDouble && !escaped) {
|
|
546
|
+
inSingle = !inSingle;
|
|
547
|
+
} else if (!inSingle && !inDouble) {
|
|
548
|
+
if (char === '[') {
|
|
549
|
+
bracketDepth += 1;
|
|
550
|
+
} else if (char === ']') {
|
|
551
|
+
bracketDepth -= 1;
|
|
552
|
+
if (bracketDepth < 0) {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
} else if (char === '{') {
|
|
556
|
+
braceDepth += 1;
|
|
557
|
+
} else if (char === '}') {
|
|
558
|
+
braceDepth -= 1;
|
|
559
|
+
if (braceDepth < 0) {
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
escaped = char === '\\' && !escaped;
|
|
566
|
+
if (char !== '\\') {
|
|
567
|
+
escaped = false;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return (
|
|
573
|
+
!tripleState.inTripleDouble &&
|
|
574
|
+
!tripleState.inTripleSingle &&
|
|
575
|
+
bracketDepth === 0 &&
|
|
576
|
+
braceDepth === 0 &&
|
|
577
|
+
!inSingle &&
|
|
578
|
+
!inDouble
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
try {
|
|
583
|
+
const source = fs.readFileSync(configPath, 'utf8');
|
|
584
|
+
if (!isStructurallySafe(source)) {
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const blocks = findAllCodexBlocks(source);
|
|
589
|
+
if (blocks.length !== 1) {
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const parsed = parseCodexBlock(blocks[0]);
|
|
594
|
+
const isConfigured =
|
|
595
|
+
!parsed.hasConflict &&
|
|
596
|
+
parsed.command === expectedCommand &&
|
|
597
|
+
Array.isArray(parsed.args) &&
|
|
598
|
+
parsed.args.length === expectedArgs.length &&
|
|
599
|
+
parsed.args.every((entry, index) => entry === expectedArgs[index]);
|
|
600
|
+
|
|
601
|
+
process.exit(isConfigured ? 0 : 1);
|
|
602
|
+
} catch {
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
"@
|
|
606
|
+
return $LASTEXITCODE -eq 0
|
|
607
|
+
}
|
|
608
|
+
finally {
|
|
609
|
+
Remove-Item Env:\MCP_CODEX_CONFIG_PATH -ErrorAction SilentlyContinue
|
|
610
|
+
}
|
|
148
611
|
}
|
|
149
612
|
|
|
150
613
|
# Add MCP server to JSON config file (PowerShell 5.1 compatible — edits JSON via node)
|
|
@@ -257,8 +720,7 @@ else {
|
|
|
257
720
|
# [3/3] Register MCP with AI apps
|
|
258
721
|
# ═══════════════════════════════════
|
|
259
722
|
Write-Step "3/3" "Register MCP with AI apps"
|
|
260
|
-
Write-Host " Automatic registration: Claude Code, Claude Desktop, Cursor, Codex CLI, Gemini CLI"
|
|
261
|
-
Write-Host " Manual setup required: Codex App, Antigravity"
|
|
723
|
+
Write-Host " Automatic registration: Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity"
|
|
262
724
|
|
|
263
725
|
$detectedNames = @()
|
|
264
726
|
$detectedTypes = @()
|
|
@@ -306,15 +768,15 @@ $codexConfigured = Test-CodexConfigConfigured $codexConfig
|
|
|
306
768
|
$codexCliCommand = Resolve-OptionalCliCommand 'codex'
|
|
307
769
|
|
|
308
770
|
if ($codexConfigured) {
|
|
309
|
-
$detectedNames += 'Codex CLI (configured)'
|
|
771
|
+
$detectedNames += 'Codex CLI/App (configured)'
|
|
310
772
|
$detectedTypes += 'codex-cli'
|
|
311
773
|
}
|
|
312
774
|
elseif ($codexCliCommand) {
|
|
313
|
-
$detectedNames += 'Codex CLI'
|
|
775
|
+
$detectedNames += 'Codex CLI/App'
|
|
314
776
|
$detectedTypes += 'codex-cli'
|
|
315
777
|
}
|
|
316
778
|
else {
|
|
317
|
-
$notDetected += 'Codex CLI (not found)'
|
|
779
|
+
$notDetected += 'Codex CLI/App (not found)'
|
|
318
780
|
}
|
|
319
781
|
|
|
320
782
|
# Gemini CLI
|
|
@@ -334,6 +796,23 @@ else {
|
|
|
334
796
|
$notDetected += "Gemini CLI (not found)"
|
|
335
797
|
}
|
|
336
798
|
|
|
799
|
+
# Antigravity (unofficial path, auto-register if found)
|
|
800
|
+
$antigravityConfig = Join-Path $env:USERPROFILE '.gemini\antigravity\mcp_config.json'
|
|
801
|
+
$antigravityConfigured = Test-AntigravityMcpConfigured $antigravityConfig
|
|
802
|
+
$antigravityDirExists = Test-Path (Join-Path $env:USERPROFILE '.gemini\antigravity')
|
|
803
|
+
|
|
804
|
+
if ($antigravityConfigured) {
|
|
805
|
+
$detectedNames += 'Antigravity (configured)'
|
|
806
|
+
$detectedTypes += 'antigravity'
|
|
807
|
+
}
|
|
808
|
+
elseif ((Test-Path $antigravityConfig) -or $antigravityDirExists) {
|
|
809
|
+
$detectedNames += 'Antigravity'
|
|
810
|
+
$detectedTypes += 'antigravity'
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
$notDetected += 'Antigravity (not found)'
|
|
814
|
+
}
|
|
815
|
+
|
|
337
816
|
if ($detectedNames.Count -eq 0) {
|
|
338
817
|
Write-Warn "No AI apps detected"
|
|
339
818
|
Write-Info "Register MCP server manually: npx -y @weppy/roblox-mcp"
|
|
@@ -429,6 +908,15 @@ else {
|
|
|
429
908
|
Write-Ok "Registered: $appName"
|
|
430
909
|
}
|
|
431
910
|
}
|
|
911
|
+
"antigravity" {
|
|
912
|
+
if ($antigravityConfigured) {
|
|
913
|
+
Write-Ok "Already configured: $appName"
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
Add-AntigravityMcpConfig $antigravityConfig
|
|
917
|
+
Write-Ok "Registered: $appName"
|
|
918
|
+
}
|
|
919
|
+
}
|
|
432
920
|
}
|
|
433
921
|
}
|
|
434
922
|
catch {
|
|
@@ -449,8 +937,7 @@ Write-Host " 1. Restart Roblox Studio"
|
|
|
449
937
|
Write-Host " 2. Look for the WROX button in the Plugins tab"
|
|
450
938
|
Write-Host " 3. Click Connect and start building with AI!"
|
|
451
939
|
Write-Host ""
|
|
452
|
-
Write-Host " Auto registration: Claude Code, Claude Desktop, Cursor, Codex CLI, Gemini CLI"
|
|
453
|
-
Write-Host " Manual setup required: Codex App, Antigravity"
|
|
940
|
+
Write-Host " Auto registration: Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity"
|
|
454
941
|
Write-Host ""
|
|
455
942
|
Write-Host " Docs: https://github.com/hope1026/weppy-roblox-mcp" -ForegroundColor DarkGray
|
|
456
943
|
Write-Host ""
|