@weppy/roblox-mcp 0.1.9 → 0.1.11

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.
Files changed (30) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +15 -0
  3. package/docs/assets/screenshots/antigravity/antigravity_mcp_raw.png +3 -0
  4. package/docs/assets/screenshots/antigravity/antigravity_mcp_services_menu.png +3 -0
  5. package/docs/assets/screenshots/antigravity/antigravity_raw_config_menu.png +3 -0
  6. package/docs/en/installation/ai-apps/antigravity.md +26 -67
  7. package/docs/en/installation/ai-apps/gemini-cli.md +24 -31
  8. package/docs/en/installation/roblox-plugin.md +1 -1
  9. package/docs/es/installation/ai-apps/antigravity.md +36 -77
  10. package/docs/es/installation/ai-apps/gemini-cli.md +51 -58
  11. package/docs/es/installation/roblox-plugin.md +1 -1
  12. package/docs/id/installation/ai-apps/antigravity.md +34 -75
  13. package/docs/id/installation/ai-apps/gemini-cli.md +42 -49
  14. package/docs/id/installation/roblox-plugin.md +1 -1
  15. package/docs/ja/installation/ai-apps/antigravity.md +22 -63
  16. package/docs/ja/installation/ai-apps/gemini-cli.md +39 -46
  17. package/docs/ja/installation/roblox-plugin.md +1 -1
  18. package/docs/ko/installation/ai-apps/antigravity.md +21 -63
  19. package/docs/ko/installation/ai-apps/gemini-cli.md +24 -31
  20. package/docs/ko/installation/roblox-plugin.md +1 -1
  21. package/docs/pt-br/installation/ai-apps/antigravity.md +36 -77
  22. package/docs/pt-br/installation/ai-apps/gemini-cli.md +47 -54
  23. package/docs/pt-br/installation/roblox-plugin.md +1 -1
  24. package/package.json +1 -1
  25. package/plugins/weppy-roblox-mcp/.claude-plugin/plugin.json +1 -1
  26. package/plugins/weppy-roblox-mcp/dist/index.js +51 -47
  27. package/plugins/weppy-roblox-mcp/skills/roblox-sync/SKILL.md +208 -105
  28. package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/post-verify.sh +12 -10
  29. package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/pre-check.sh +8 -5
  30. package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/update-metadata.sh +1 -1
@@ -9,9 +9,15 @@ hooks:
9
9
  hooks:
10
10
  - type: command
11
11
  command: |
12
- if [ -d "roblox-studio-sync" ]; then
12
+ SYNC_DIR=""
13
+ if [ -d "roblox-project-sync" ]; then
14
+ SYNC_DIR="roblox-project-sync"
15
+ elif [ -d "roblox-studio-sync" ]; then
16
+ SYNC_DIR="roblox-studio-sync"
17
+ fi
18
+ if [ -n "$SYNC_DIR" ]; then
13
19
  timestamp=$(date +"%Y-%m-%d %H:%M:%S")
14
- echo "[$timestamp] Modified: $TOOL_NAME" >> "roblox-studio-sync/changes.log"
20
+ echo "[$timestamp] Modified: $TOOL_NAME" >> "$SYNC_DIR/changes.log"
15
21
  fi
16
22
  ---
17
23
 
@@ -19,88 +25,152 @@ hooks:
19
25
 
20
26
  **CRITICAL: This skill BLOCKS until sync is fully verified. Do NOT return early.**
21
27
 
28
+ ## Sync Mode Detection
29
+
30
+ This skill supports two sync modes:
31
+
32
+ ### Project Sync Mode (Automatic, Preferred)
33
+
34
+ When `.sync-meta.json` exists in `roblox-project-sync/`, the Roblox Studio plugin automatically syncs the instance tree to the local filesystem. **No MCP tool calls needed.**
35
+
36
+ **Detection:**
37
+ ```bash
38
+ if [ -f "roblox-project-sync/.sync-meta.json" ]; then
39
+ # Project Sync active -- skip MCP calls, just read files
40
+ fi
41
+ ```
42
+
43
+ **When Project Sync is active:**
44
+ 1. Skip Steps 2-4 (no MCP tool calls needed)
45
+ 2. Read files directly from `roblox-project-sync/explorer/`
46
+ 3. Verify sync freshness via `.sync-meta.json` timestamps
47
+ 4. All script sources are already on disk as `.luau` files
48
+
49
+ ### Legacy MCP Mode (Fallback)
50
+
51
+ When Project Sync is NOT active, fall back to MCP tool calls (`get_project_structure`, `get_script_source`) to populate `roblox-project-sync/explorer/`.
52
+
53
+ ---
54
+
22
55
  ## Cache Structure (Roblox Studio Mirror)
23
56
 
24
- The explorer folder mirrors Roblox Studio's hierarchy exactly:
57
+ The explorer folder mirrors Roblox Studio's hierarchy:
25
58
 
26
59
  ```
27
- roblox-studio-sync/
28
- ├── last-sync.txt # ISO timestamp of last successful sync
29
- ├── connection-status.txt # "connected" or "disconnected"
30
- ├── rojo-detected.txt # "true" or "false"
31
- ├── changes.log # MCP tool usage log
32
- ├── activity.log # All MCP activity
60
+ roblox-project-sync/
61
+ ├── .sync-meta.json # Sync metadata (placeId, timestamps, config)
62
+ ├── .sync-index.json # Per-file hash tracking
63
+ ├── changes.log # Change history (auto-flushed)
33
64
  ├── explorer/ # Mirrors Studio hierarchy
34
65
  │ ├── Workspace/
35
- │ │ ├── _index.json # Service summary (className, childCount, path)
36
- │ │ ├── Camera.json # Instance: { className, properties }
37
- │ │ ├── Terrain.json # Instance: { className, properties }
38
- │ │ └── MyModel/ # Model becomes folder
39
- │ │ ├── _index.json # Model summary
40
- │ │ ├── Part1.json # Part properties
41
- │ │ └── MyScript.server.lua # Script SOURCE (full text)
66
+ │ │ ├── _tree.json # Service tree summary
67
+ │ │ ├── _props.json # Service properties
68
+ │ │ ├── MyModel/ # Model becomes folder
69
+ │ │ │ ├── _props.json # Model properties
70
+ │ │├── Part1/
71
+ │ │ │ │ └── _props.json
72
+ │ │└── MyScript.server.luau # Script SOURCE (full text)
73
+ │ │ └── SpawnLocation/
74
+ │ │ └── _props.json
42
75
  │ ├── ServerScriptService/
43
- │ │ ├── _index.json
44
- │ │ └── GameManager.server.lua # Script source file
76
+ │ │ ├── _tree.json
77
+ │ │ └── GameManager.server.luau
45
78
  │ ├── ReplicatedStorage/
46
- │ │ ├── _index.json
47
- │ │ └── Events/
48
- │ │ └── _index.json
79
+ │ │ ├── _tree.json
80
+ │ │ └── SharedModule.module.luau
49
81
  │ ├── ServerStorage/
50
- │ │ └── _index.json
82
+ │ │ └── _tree.json
51
83
  │ ├── StarterGui/
52
- │ │ └── _index.json
84
+ │ │ └── _tree.json
53
85
  │ ├── StarterPlayer/
54
- │ │ ├── _index.json
86
+ │ │ ├── _tree.json
55
87
  │ │ └── StarterPlayerScripts/
56
- │ │ └── _index.json
88
+ │ │ └── _tree.json
57
89
  │ └── Lighting/
58
- │ ├── _index.json
59
- ├── Atmosphere.json
60
- └── Sky.json
61
- ├── snapshots/ # Point-in-time snapshots
62
- └── screenshots/ # Visual captures
90
+ │ ├── _tree.json
91
+ └── Atmosphere/
92
+ └── _props.json
93
+ └── snapshots/ # Point-in-time snapshots (.tar.gz)
94
+ └── _index.json # Snapshot registry
63
95
  ```
64
96
 
65
97
  ### File Formats
66
98
 
67
- **_index.json (Service/Folder Summary):**
99
+ **_tree.json (Service/Container Tree Summary):**
68
100
  ```json
69
101
  {
70
102
  "name": "Workspace",
71
103
  "className": "Workspace",
72
- "path": "game.Workspace",
73
104
  "childCount": 5,
74
- "children": ["Camera", "Terrain", "SpawnLocation", "Monsters", "Bosque"],
75
- "syncedAt": "2026-01-28T21:00:00+09:00"
105
+ "children": [
106
+ { "name": "SpawnLocation", "className": "SpawnLocation", "childCount": 0 },
107
+ { "name": "MyModel", "className": "Model", "childCount": 3, "children": [...] }
108
+ ],
109
+ "syncedAt": "2026-02-09T12:00:00.000Z"
76
110
  }
77
111
  ```
78
112
 
79
- **Instance.json (Part, Model, etc.):**
113
+ **_props.json (Instance Properties):**
80
114
  ```json
81
115
  {
82
116
  "name": "SpawnLocation",
83
117
  "className": "SpawnLocation",
84
- "path": "game.Workspace.SpawnLocation",
85
118
  "properties": {
86
- "Position": [160, 26, -40],
87
- "Size": [6, 1, 6],
119
+ "Position": { "x": 160, "y": 26, "z": -40 },
120
+ "Size": { "x": 6, "y": 1, "z": 6 },
88
121
  "Anchored": true,
89
122
  "Neutral": true
90
- }
123
+ },
124
+ "attributes": { "SpawnPriority": 1 },
125
+ "tags": ["PlayerSpawn"]
91
126
  }
92
127
  ```
93
128
 
94
- **Script Files (.lua):**
95
- - `Name.server.lua` → Server Script
96
- - `Name.client.lua` → Local Script
97
- - `Name.lua` → Module Script
129
+ **.sync-meta.json (Sync Metadata):**
130
+ ```json
131
+ {
132
+ "version": 1,
133
+ "placeId": 12345,
134
+ "placeName": "My Game",
135
+ "lastFullSync": "2026-02-09T12:00:00.000Z",
136
+ "lastIncrementalSync": "2026-02-09T12:05:30.000Z",
137
+ "instanceCount": 1234,
138
+ "scriptCount": 56,
139
+ "syncMode": "mirror",
140
+ "excludePatterns": ["*.Terrain", "*.Camera"],
141
+ "propertyMode": "common"
142
+ }
143
+ ```
144
+
145
+ **Script Files (.luau):**
146
+ - `Name.server.luau` -- Server Script
147
+ - `Name.client.luau` -- Local Script
148
+ - `Name.module.luau` -- Module Script
149
+ - Scripts with children: `Name/init.server.luau` (directory with init file)
150
+ - Scripts without children: `Name.server.luau` (flat file in parent dir)
98
151
  - Contains full script source code
99
152
 
100
153
  ---
101
154
 
102
155
  ## Mandatory Workflow
103
156
 
157
+ ### Step 0: Detect Sync Mode
158
+
159
+ ```bash
160
+ # Check for Project Sync first
161
+ if [ -f "roblox-project-sync/.sync-meta.json" ]; then
162
+ echo "Project Sync active"
163
+ # Check freshness
164
+ LAST_SYNC=$(grep -o '"lastFullSync":"[^"]*"' roblox-project-sync/.sync-meta.json | cut -d'"' -f4)
165
+ if [ -n "$LAST_SYNC" ]; then
166
+ echo "Last sync: $LAST_SYNC"
167
+ # Skip to Step 6 (verify only)
168
+ fi
169
+ fi
170
+ ```
171
+
172
+ If Project Sync is active AND data is fresh (< 30 minutes old), skip directly to verification.
173
+
104
174
  ### Step 1: Run Pre-Check Script (BLOCKING)
105
175
 
106
176
  ```bash
@@ -115,14 +185,18 @@ roblox-studio-sync/
115
185
  | 11 | Studio not connected | Script WAITS for user |
116
186
  | 10/12/13 | Error | Report and STOP |
117
187
 
118
- ### Step 2: Load MCP Tools
188
+ ### Step 2: Load MCP Tools (Legacy Mode Only)
189
+
190
+ Skip this step if Project Sync is active.
119
191
 
120
192
  ```
121
193
  ToolSearch: "+robloxstudio project structure"
122
194
  ToolSearch: "+robloxstudio get_script_source"
123
195
  ```
124
196
 
125
- ### Step 3: Fetch Service Structures
197
+ ### Step 3: Fetch Service Structures (Legacy Mode Only)
198
+
199
+ Skip this step if Project Sync is active.
126
200
 
127
201
  Call `get_project_structure` for ALL services in parallel:
128
202
 
@@ -136,24 +210,25 @@ get_project_structure({ rootPath: "game.StarterGui", depth: 10 })
136
210
  get_project_structure({ rootPath: "game.StarterPlayer", depth: 10 })
137
211
  ```
138
212
 
139
- ### Step 4: Create Folder Hierarchy
213
+ ### Step 4: Create Folder Hierarchy (Legacy Mode Only)
140
214
 
141
- For each service response, create folder structure:
215
+ Skip this step if Project Sync is active.
216
+
217
+ For each service response, create folder structure under `roblox-project-sync/explorer/`:
142
218
 
143
219
  ```typescript
144
220
  function syncService(serviceName: string, data: any) {
145
- const baseDir = `roblox-studio-sync/explorer/${serviceName}`;
146
-
147
- // Create service folder
221
+ const baseDir = `roblox-project-sync/explorer/${serviceName}`;
148
222
  mkdir(baseDir);
149
223
 
150
- // Write _index.json
151
- Write(`${baseDir}/_index.json`, JSON.stringify({
224
+ // Write _tree.json
225
+ Write(`${baseDir}/_tree.json`, JSON.stringify({
152
226
  name: data.structure.name,
153
227
  className: data.structure.className,
154
- path: data.structure.path,
155
228
  childCount: data.structure.childCount,
156
- children: data.structure.children?.map(c => c.name) || [],
229
+ children: data.structure.children?.map(c => ({
230
+ name: c.name, className: c.className, childCount: c.childCount
231
+ })) || [],
157
232
  syncedAt: new Date().toISOString()
158
233
  }, null, 2));
159
234
 
@@ -168,35 +243,33 @@ async function syncInstance(parentDir: string, instance: any) {
168
243
  const isContainer = instance.childCount > 0 || ["Folder", "Model"].includes(instance.className);
169
244
 
170
245
  if (isScript) {
171
- // Fetch and save script source
172
246
  const source = await get_script_source({ path: instance.path });
173
- const ext = instance.className === "Script" ? ".server.lua"
174
- : instance.className === "LocalScript" ? ".client.lua"
175
- : ".lua";
247
+ const ext = instance.className === "Script" ? ".server.luau"
248
+ : instance.className === "LocalScript" ? ".client.luau"
249
+ : ".module.luau";
176
250
  Write(`${parentDir}/${instance.name}${ext}`, source.source);
177
251
  } else if (isContainer) {
178
- // Create subfolder
179
252
  const subDir = `${parentDir}/${instance.name}`;
180
253
  mkdir(subDir);
181
- Write(`${subDir}/_index.json`, JSON.stringify({
254
+
255
+ // Write _props.json for the container
256
+ Write(`${subDir}/_props.json`, JSON.stringify({
182
257
  name: instance.name,
183
258
  className: instance.className,
184
- path: instance.path,
185
- childCount: instance.childCount,
186
- children: instance.children?.map(c => c.name) || []
259
+ properties: instance.properties || {}
187
260
  }, null, 2));
188
261
 
189
- // Recurse into children
190
262
  for (const child of instance.children || []) {
191
263
  syncInstance(subDir, child);
192
264
  }
193
265
  } else {
194
- // Simple instance - save properties
195
- Write(`${parentDir}/${instance.name}.json`, JSON.stringify({
266
+ // Instance with properties
267
+ const subDir = `${parentDir}/${instance.name}`;
268
+ mkdir(subDir);
269
+ Write(`${subDir}/_props.json`, JSON.stringify({
196
270
  name: instance.name,
197
271
  className: instance.className,
198
- path: instance.path,
199
- childCount: instance.childCount
272
+ properties: instance.properties || {}
200
273
  }, null, 2));
201
274
  }
202
275
  }
@@ -205,7 +278,7 @@ async function syncInstance(parentDir: string, instance: any) {
205
278
  ### Step 5: Update Metadata
206
279
 
207
280
  ```bash
208
- ./.claude/skills/roblox-sync/scripts/update-metadata.sh
281
+ ./.claude/skills/roblox-sync/scripts/update-metadata.sh roblox-project-sync
209
282
  ```
210
283
 
211
284
  ### Step 6: Verify Completion (REQUIRED)
@@ -215,19 +288,20 @@ async function syncInstance(parentDir: string, instance: any) {
215
288
  ```
216
289
 
217
290
  **Verification checks:**
218
- 1. All required service folders exist
219
- 2. Each folder has valid `_index.json`
220
- 3. Workspace has children (Camera, Terrain minimum)
221
- 4. Timestamp is current
291
+ 1. All required service folders exist
292
+ 2. Each folder has valid `_tree.json`
293
+ 3. Workspace has children (in _tree.json)
294
+ 4. Timestamp is current (from .sync-meta.json or last-sync.txt)
222
295
 
223
296
  ### Step 7: Report Success
224
297
 
225
298
  ```
226
- Sync Complete
299
+ Sync Complete
300
+ - Mode: Project Sync (automatic) / Legacy (MCP calls)
227
301
  - Services: Workspace, Lighting, ReplicatedStorage, ServerStorage, ServerScriptService, StarterGui, StarterPlayer
228
302
  - Scripts synced: {count}
229
- - Timestamp: {last-sync.txt}
230
- - Rojo mode: {rojo-detected.txt}
303
+ - Instances: {count}
304
+ - Last sync: {timestamp}
231
305
  ```
232
306
 
233
307
  ---
@@ -238,7 +312,7 @@ async function syncInstance(parentDir: string, instance: any) {
238
312
 
239
313
  | Service | Minimum Children |
240
314
  |---------|------------------|
241
- | Workspace | Camera, Terrain |
315
+ | Workspace | At least 1 child |
242
316
  | Lighting | (any) |
243
317
  | StarterPlayer | StarterPlayerScripts |
244
318
 
@@ -255,29 +329,36 @@ These can be empty for new projects:
255
329
  ```typescript
256
330
  function validateSync(): boolean {
257
331
  const errors: string[] = [];
332
+ const syncDir = "roblox-project-sync";
333
+
334
+ // Check .sync-meta.json for Project Sync mode
335
+ const metaPath = `${syncDir}/.sync-meta.json`;
336
+ if (fileExists(metaPath)) {
337
+ const meta = readJSON(metaPath);
338
+ // Check freshness via lastFullSync
339
+ if (meta.lastFullSync) {
340
+ const syncAge = Date.now() - Date.parse(meta.lastFullSync);
341
+ if (syncAge > 30 * 60 * 1000) {
342
+ errors.push("Sync data is stale (>30 minutes old)");
343
+ }
344
+ }
345
+ }
258
346
 
259
- // Check Workspace has children
260
- const wsIndex = readJSON("explorer/Workspace/_index.json");
261
- if (!wsIndex || wsIndex.childCount < 2) {
262
- errors.push("Workspace must have at least Camera and Terrain");
347
+ // Check Workspace tree
348
+ const wsTree = readJSON(`${syncDir}/explorer/Workspace/_tree.json`);
349
+ if (!wsTree || wsTree.childCount < 1) {
350
+ errors.push("Workspace must have at least 1 child");
263
351
  }
264
352
 
265
- // Check all required _index.json files exist
353
+ // Check all required _tree.json files exist
266
354
  const required = ["Workspace", "Lighting", "ReplicatedStorage",
267
355
  "ServerStorage", "ServerScriptService", "StarterGui", "StarterPlayer"];
268
356
  for (const svc of required) {
269
- if (!fileExists(`explorer/${svc}/_index.json`)) {
270
- errors.push(`Missing ${svc}/_index.json`);
357
+ if (!fileExists(`${syncDir}/explorer/${svc}/_tree.json`)) {
358
+ errors.push(`Missing ${svc}/_tree.json`);
271
359
  }
272
360
  }
273
361
 
274
- // Check timestamp freshness (max 30 minutes)
275
- const lastSync = readFile("last-sync.txt");
276
- const syncAge = Date.now() - Date.parse(lastSync);
277
- if (syncAge > 30 * 60 * 1000) {
278
- errors.push("Sync data is stale (>30 minutes old)");
279
- }
280
-
281
362
  return errors.length === 0;
282
363
  }
283
364
  ```
@@ -286,27 +367,49 @@ function validateSync(): boolean {
286
367
 
287
368
  ## Script Sync Details
288
369
 
289
- When syncing scripts, fetch full source:
370
+ In **Project Sync mode**, scripts are already on disk. Just read them directly:
371
+
372
+ ```typescript
373
+ // Scripts are at:
374
+ // - Without children: ParentDir/ScriptName.server.luau
375
+ // - With children: ScriptName/init.server.luau
376
+
377
+ // Extension mapping:
378
+ const ext = {
379
+ "Script": ".server.luau",
380
+ "LocalScript": ".client.luau",
381
+ "ModuleScript": ".module.luau"
382
+ }[instance.className];
383
+ ```
384
+
385
+ In **Legacy mode**, fetch via MCP:
290
386
 
291
387
  ```typescript
292
- // For each Script/LocalScript/ModuleScript found:
293
388
  const scriptSource = await mcp__robloxstudio__get_script_source({
294
389
  path: instance.path
295
390
  });
296
391
 
297
- // Determine file extension
298
392
  const ext = {
299
- "Script": ".server.lua",
300
- "LocalScript": ".client.lua",
301
- "ModuleScript": ".lua"
393
+ "Script": ".server.luau",
394
+ "LocalScript": ".client.luau",
395
+ "ModuleScript": ".module.luau"
302
396
  }[instance.className];
303
397
 
304
- // Save to file
305
398
  Write(`${parentDir}/${instance.name}${ext}`, scriptSource.source);
306
399
  ```
307
400
 
308
401
  ---
309
402
 
403
+ ## Migration from roblox-studio-sync
404
+
405
+ If `roblox-studio-sync/` exists but `roblox-project-sync/` does not:
406
+ 1. The old folder uses `_index.json` and `.lua` extensions
407
+ 2. Create `roblox-project-sync/` with the new structure
408
+ 3. Do NOT delete `roblox-studio-sync/` (user may want to keep it)
409
+ 4. Future syncs will use `roblox-project-sync/` exclusively
410
+
411
+ ---
412
+
310
413
  ## Error Handling
311
414
 
312
415
  | Error | Action |
@@ -337,7 +440,7 @@ When the user reports "plugin shows connected but sync doesn't work":
337
440
 
338
441
  | Argument | Action |
339
442
  |----------|--------|
340
- | `full` | Execute full sync workflow (Steps 1-7) |
443
+ | `full` | Execute full sync workflow (Steps 0-7) |
341
444
  | `verify` | Run verification only (Step 6) |
342
445
  | (none) | Same as `full` |
343
446
 
@@ -347,12 +450,12 @@ When the user reports "plugin shows connected but sync doesn't work":
347
450
 
348
451
  **This skill is NOT complete until ALL conditions are true:**
349
452
 
350
- 1. MCP connection verified
351
- 2. All 7 service folders created with `_index.json`
352
- 3. Workspace has children (childCount >= 2)
353
- 4. All scripts have `.lua` source files
354
- 5. `post-verify.sh` returns exit 0
355
- 6. `last-sync.txt` has current timestamp
453
+ 1. MCP connection verified (or Project Sync active)
454
+ 2. All 7+ service folders created with `_tree.json`
455
+ 3. Workspace has children (childCount >= 1)
456
+ 4. All scripts have `.luau` source files
457
+ 5. `post-verify.sh` returns exit 0
458
+ 6. Timestamps are current
356
459
 
357
460
  **If ANY fails, DO NOT return success.**
358
461
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  set -euo pipefail
14
14
 
15
- SYNC_DIR="${SYNC_DIR:-roblox-studio-sync}"
15
+ SYNC_DIR="${SYNC_DIR:-roblox-project-sync}"
16
16
  EXPLORER_DIR="$SYNC_DIR/explorer"
17
17
 
18
18
  # Required service folders
@@ -30,36 +30,38 @@ log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
30
30
  verify_service() {
31
31
  local service="$1"
32
32
  local service_dir="$EXPLORER_DIR/$service"
33
- local index_file="$service_dir/_index.json"
34
-
35
33
  # Check folder exists
36
34
  if [ ! -d "$service_dir" ]; then
37
35
  log_fail "$service: Folder not found"
38
36
  return 1
39
37
  fi
40
38
 
41
- # Check _index.json exists
39
+ # Check _tree.json (new format) or _index.json (legacy) exists
40
+ local index_file="$service_dir/_tree.json"
41
+ if [ ! -f "$index_file" ]; then
42
+ index_file="$service_dir/_index.json"
43
+ fi
42
44
  if [ ! -f "$index_file" ]; then
43
- log_fail "$service: _index.json not found"
45
+ log_fail "$service: _tree.json not found"
44
46
  return 1
45
47
  fi
46
48
 
47
- # Check _index.json has content
49
+ # Check file has content
48
50
  local size
49
51
  size=$(stat -f %z "$index_file" 2>/dev/null || stat -c %s "$index_file" 2>/dev/null || echo "0")
50
52
  if [ "$size" -lt 20 ]; then
51
- log_fail "$service: _index.json too small (${size} bytes)"
53
+ log_fail "$service: $(basename $index_file) too small (${size} bytes)"
52
54
  return 1
53
55
  fi
54
56
 
55
57
  # Check JSON has required fields
56
58
  if ! grep -q '"name"' "$index_file" 2>/dev/null; then
57
- log_fail "$service: _index.json missing 'name' field"
59
+ log_fail "$service: $(basename $index_file) missing 'name' field"
58
60
  return 1
59
61
  fi
60
62
 
61
63
  if ! grep -q '"className"' "$index_file" 2>/dev/null; then
62
- log_fail "$service: _index.json missing 'className' field"
64
+ log_fail "$service: $(basename $index_file) missing 'className' field"
63
65
  return 1
64
66
  fi
65
67
 
@@ -133,7 +135,7 @@ main() {
133
135
  # Count total scripts synced
134
136
  local script_count=0
135
137
  if [ -d "$EXPLORER_DIR" ]; then
136
- script_count=$(find "$EXPLORER_DIR" -name "*.lua" -type f 2>/dev/null | wc -l | tr -d ' ')
138
+ script_count=$(find "$EXPLORER_DIR" \( -name "*.luau" -o -name "*.lua" \) -type f 2>/dev/null | wc -l | tr -d ' ')
137
139
  fi
138
140
  echo "Scripts synced: $script_count"
139
141
 
@@ -18,7 +18,7 @@
18
18
  set -euo pipefail
19
19
 
20
20
  # Configuration
21
- SYNC_DIR="${SYNC_DIR:-roblox-studio-sync}"
21
+ SYNC_DIR="${SYNC_DIR:-roblox-project-sync}"
22
22
  MCP_PORT="${MCP_PORT:-3002}"
23
23
  MAX_RETRIES="${MAX_RETRIES:-60}" # Max retries for each phase (5 minutes at 5s intervals)
24
24
  RETRY_INTERVAL=5
@@ -154,19 +154,22 @@ verify_sync_data() {
154
154
  # Check each required service has a folder with _index.json
155
155
  for service in "${REQUIRED_SERVICES[@]}"; do
156
156
  local service_dir="$explorer_dir/${service}"
157
- local index_file="$service_dir/_index.json"
158
-
159
157
  if [ ! -d "$service_dir" ]; then
160
158
  missing_services+=("$service")
161
159
  continue
162
160
  fi
163
161
 
162
+ # Check for _tree.json (new format) or _index.json (legacy)
163
+ local index_file="$service_dir/_tree.json"
164
+ if [ ! -f "$index_file" ]; then
165
+ index_file="$service_dir/_index.json"
166
+ fi
164
167
  if [ ! -f "$index_file" ]; then
165
- invalid_services+=("$service (missing _index.json)")
168
+ invalid_services+=("$service (missing _tree.json)")
166
169
  continue
167
170
  fi
168
171
 
169
- # Check _index.json is not empty and has valid structure
172
+ # Check file is not empty and has valid structure
170
173
  local file_size
171
174
  file_size=$(stat -f %z "$index_file" 2>/dev/null || stat -c %s "$index_file" 2>/dev/null || echo "0")
172
175
  if [ "$file_size" -lt 20 ]; then
@@ -12,7 +12,7 @@
12
12
 
13
13
  set -euo pipefail
14
14
 
15
- SYNC_DIR="${1:-roblox-studio-sync}"
15
+ SYNC_DIR="${1:-roblox-project-sync}"
16
16
 
17
17
  if [ ! -d "$SYNC_DIR" ]; then
18
18
  echo "ERROR: Sync directory not found: $SYNC_DIR"