@weppy/roblox-mcp 0.1.11 → 1.0.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 +45 -10
- package/README.md +6 -0
- package/docs/en/installation/roblox-plugin.md +10 -5
- package/docs/en/pro-upgrade.md +36 -30
- package/docs/en/tools/overview.md +255 -95
- package/docs/es/README.md +6 -0
- package/docs/es/installation/README.md +6 -5
- package/docs/es/installation/roblox-plugin.md +29 -24
- package/docs/es/pro-upgrade.md +39 -33
- package/docs/es/tools/overview.md +4 -0
- package/docs/id/README.md +6 -0
- package/docs/id/installation/roblox-plugin.md +28 -23
- package/docs/id/pro-upgrade.md +36 -30
- package/docs/id/tools/overview.md +4 -0
- package/docs/ja/README.md +6 -0
- package/docs/ja/installation/README.md +5 -5
- package/docs/ja/installation/roblox-plugin.md +32 -27
- package/docs/ja/pro-upgrade.md +38 -32
- package/docs/ja/tools/overview.md +4 -0
- package/docs/ko/README.md +6 -0
- package/docs/ko/installation/roblox-plugin.md +10 -5
- package/docs/ko/pro-upgrade.md +36 -30
- package/docs/ko/tools/overview.md +255 -95
- package/docs/pt-br/README.md +6 -0
- package/docs/pt-br/installation/roblox-plugin.md +28 -23
- package/docs/pt-br/pro-upgrade.md +39 -33
- package/docs/pt-br/tools/overview.md +4 -0
- package/package.json +4 -2
- package/plugins/weppy-roblox-mcp/.claude-plugin/plugin.json +1 -1
- package/plugins/weppy-roblox-mcp/dist/index.js +70 -98
- package/plugins/weppy-roblox-mcp/skills/roblox-game-dev/SKILL.md +0 -155
- package/plugins/weppy-roblox-mcp/skills/roblox-game-dev/references/animations.json +0 -34
- package/plugins/weppy-roblox-mcp/skills/roblox-game-dev/references/mcp-tools.md +0 -220
- package/plugins/weppy-roblox-mcp/skills/roblox-sync/SKILL.md +0 -492
- package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/post-verify.sh +0 -162
- package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/pre-check.sh +0 -307
- package/plugins/weppy-roblox-mcp/skills/roblox-sync/scripts/update-metadata.sh +0 -27
|
@@ -1,492 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: roblox-sync
|
|
3
|
-
description: Synchronize Roblox Studio state with local cache. BLOCKING - does not return until sync is verified complete.
|
|
4
|
-
argument-hint: "[full|verify]"
|
|
5
|
-
user-invocable: false
|
|
6
|
-
hooks:
|
|
7
|
-
PostToolUse:
|
|
8
|
-
- matcher: "mcp__robloxstudio__(create|delete|set|move|rename|clone|edit|insert|terrain).*"
|
|
9
|
-
hooks:
|
|
10
|
-
- type: command
|
|
11
|
-
command: |
|
|
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
|
|
19
|
-
timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
20
|
-
echo "[$timestamp] Modified: $TOOL_NAME" >> "$SYNC_DIR/changes.log"
|
|
21
|
-
fi
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
# Roblox Sync Skill
|
|
25
|
-
|
|
26
|
-
**CRITICAL: This skill BLOCKS until sync is fully verified. Do NOT return early.**
|
|
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
|
-
|
|
55
|
-
## Cache Structure (Roblox Studio Mirror)
|
|
56
|
-
|
|
57
|
-
The explorer folder mirrors Roblox Studio's hierarchy:
|
|
58
|
-
|
|
59
|
-
```
|
|
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)
|
|
64
|
-
├── explorer/ # Mirrors Studio hierarchy
|
|
65
|
-
│ ├── Workspace/
|
|
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
|
|
75
|
-
│ ├── ServerScriptService/
|
|
76
|
-
│ │ ├── _tree.json
|
|
77
|
-
│ │ └── GameManager.server.luau
|
|
78
|
-
│ ├── ReplicatedStorage/
|
|
79
|
-
│ │ ├── _tree.json
|
|
80
|
-
│ │ └── SharedModule.module.luau
|
|
81
|
-
│ ├── ServerStorage/
|
|
82
|
-
│ │ └── _tree.json
|
|
83
|
-
│ ├── StarterGui/
|
|
84
|
-
│ │ └── _tree.json
|
|
85
|
-
│ ├── StarterPlayer/
|
|
86
|
-
│ │ ├── _tree.json
|
|
87
|
-
│ │ └── StarterPlayerScripts/
|
|
88
|
-
│ │ └── _tree.json
|
|
89
|
-
│ └── Lighting/
|
|
90
|
-
│ ├── _tree.json
|
|
91
|
-
│ └── Atmosphere/
|
|
92
|
-
│ └── _props.json
|
|
93
|
-
└── snapshots/ # Point-in-time snapshots (.tar.gz)
|
|
94
|
-
└── _index.json # Snapshot registry
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### File Formats
|
|
98
|
-
|
|
99
|
-
**_tree.json (Service/Container Tree Summary):**
|
|
100
|
-
```json
|
|
101
|
-
{
|
|
102
|
-
"name": "Workspace",
|
|
103
|
-
"className": "Workspace",
|
|
104
|
-
"childCount": 5,
|
|
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"
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
**_props.json (Instance Properties):**
|
|
114
|
-
```json
|
|
115
|
-
{
|
|
116
|
-
"name": "SpawnLocation",
|
|
117
|
-
"className": "SpawnLocation",
|
|
118
|
-
"properties": {
|
|
119
|
-
"Position": { "x": 160, "y": 26, "z": -40 },
|
|
120
|
-
"Size": { "x": 6, "y": 1, "z": 6 },
|
|
121
|
-
"Anchored": true,
|
|
122
|
-
"Neutral": true
|
|
123
|
-
},
|
|
124
|
-
"attributes": { "SpawnPriority": 1 },
|
|
125
|
-
"tags": ["PlayerSpawn"]
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
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)
|
|
151
|
-
- Contains full script source code
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## Mandatory Workflow
|
|
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
|
-
|
|
174
|
-
### Step 1: Run Pre-Check Script (BLOCKING)
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
./.claude/skills/roblox-sync/scripts/pre-check.sh
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Exit codes:**
|
|
181
|
-
| Code | Meaning | Action |
|
|
182
|
-
|------|---------|--------|
|
|
183
|
-
| 0 | Already synced | Skip to Step 6 (verify only) |
|
|
184
|
-
| 100 | Connection OK, sync needed | Proceed to Step 2 |
|
|
185
|
-
| 11 | Studio not connected | Script WAITS for user |
|
|
186
|
-
| 10/12/13 | Error | Report and STOP |
|
|
187
|
-
|
|
188
|
-
### Step 2: Load MCP Tools (Legacy Mode Only)
|
|
189
|
-
|
|
190
|
-
Skip this step if Project Sync is active.
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
ToolSearch: "+robloxstudio project structure"
|
|
194
|
-
ToolSearch: "+robloxstudio get_script_source"
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Step 3: Fetch Service Structures (Legacy Mode Only)
|
|
198
|
-
|
|
199
|
-
Skip this step if Project Sync is active.
|
|
200
|
-
|
|
201
|
-
Call `get_project_structure` for ALL services in parallel:
|
|
202
|
-
|
|
203
|
-
```javascript
|
|
204
|
-
get_project_structure({ rootPath: "game.Workspace", depth: 10 })
|
|
205
|
-
get_project_structure({ rootPath: "game.Lighting", depth: 5 })
|
|
206
|
-
get_project_structure({ rootPath: "game.ReplicatedStorage", depth: 10 })
|
|
207
|
-
get_project_structure({ rootPath: "game.ServerStorage", depth: 10 })
|
|
208
|
-
get_project_structure({ rootPath: "game.ServerScriptService", depth: 10 })
|
|
209
|
-
get_project_structure({ rootPath: "game.StarterGui", depth: 10 })
|
|
210
|
-
get_project_structure({ rootPath: "game.StarterPlayer", depth: 10 })
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Step 4: Create Folder Hierarchy (Legacy Mode Only)
|
|
214
|
-
|
|
215
|
-
Skip this step if Project Sync is active.
|
|
216
|
-
|
|
217
|
-
For each service response, create folder structure under `roblox-project-sync/explorer/`:
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
function syncService(serviceName: string, data: any) {
|
|
221
|
-
const baseDir = `roblox-project-sync/explorer/${serviceName}`;
|
|
222
|
-
mkdir(baseDir);
|
|
223
|
-
|
|
224
|
-
// Write _tree.json
|
|
225
|
-
Write(`${baseDir}/_tree.json`, JSON.stringify({
|
|
226
|
-
name: data.structure.name,
|
|
227
|
-
className: data.structure.className,
|
|
228
|
-
childCount: data.structure.childCount,
|
|
229
|
-
children: data.structure.children?.map(c => ({
|
|
230
|
-
name: c.name, className: c.className, childCount: c.childCount
|
|
231
|
-
})) || [],
|
|
232
|
-
syncedAt: new Date().toISOString()
|
|
233
|
-
}, null, 2));
|
|
234
|
-
|
|
235
|
-
// Process children recursively
|
|
236
|
-
for (const child of data.structure.children || []) {
|
|
237
|
-
syncInstance(baseDir, child);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function syncInstance(parentDir: string, instance: any) {
|
|
242
|
-
const isScript = ["Script", "LocalScript", "ModuleScript"].includes(instance.className);
|
|
243
|
-
const isContainer = instance.childCount > 0 || ["Folder", "Model"].includes(instance.className);
|
|
244
|
-
|
|
245
|
-
if (isScript) {
|
|
246
|
-
const source = await get_script_source({ path: instance.path });
|
|
247
|
-
const ext = instance.className === "Script" ? ".server.luau"
|
|
248
|
-
: instance.className === "LocalScript" ? ".client.luau"
|
|
249
|
-
: ".module.luau";
|
|
250
|
-
Write(`${parentDir}/${instance.name}${ext}`, source.source);
|
|
251
|
-
} else if (isContainer) {
|
|
252
|
-
const subDir = `${parentDir}/${instance.name}`;
|
|
253
|
-
mkdir(subDir);
|
|
254
|
-
|
|
255
|
-
// Write _props.json for the container
|
|
256
|
-
Write(`${subDir}/_props.json`, JSON.stringify({
|
|
257
|
-
name: instance.name,
|
|
258
|
-
className: instance.className,
|
|
259
|
-
properties: instance.properties || {}
|
|
260
|
-
}, null, 2));
|
|
261
|
-
|
|
262
|
-
for (const child of instance.children || []) {
|
|
263
|
-
syncInstance(subDir, child);
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
// Instance with properties
|
|
267
|
-
const subDir = `${parentDir}/${instance.name}`;
|
|
268
|
-
mkdir(subDir);
|
|
269
|
-
Write(`${subDir}/_props.json`, JSON.stringify({
|
|
270
|
-
name: instance.name,
|
|
271
|
-
className: instance.className,
|
|
272
|
-
properties: instance.properties || {}
|
|
273
|
-
}, null, 2));
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Step 5: Update Metadata
|
|
279
|
-
|
|
280
|
-
```bash
|
|
281
|
-
./.claude/skills/roblox-sync/scripts/update-metadata.sh roblox-project-sync
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Step 6: Verify Completion (REQUIRED)
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
./.claude/skills/roblox-sync/scripts/post-verify.sh
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**Verification checks:**
|
|
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)
|
|
295
|
-
|
|
296
|
-
### Step 7: Report Success
|
|
297
|
-
|
|
298
|
-
```
|
|
299
|
-
Sync Complete
|
|
300
|
-
- Mode: Project Sync (automatic) / Legacy (MCP calls)
|
|
301
|
-
- Services: Workspace, Lighting, ReplicatedStorage, ServerStorage, ServerScriptService, StarterGui, StarterPlayer
|
|
302
|
-
- Scripts synced: {count}
|
|
303
|
-
- Instances: {count}
|
|
304
|
-
- Last sync: {timestamp}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Data Validation Rules
|
|
310
|
-
|
|
311
|
-
### Critical Services (MUST have content)
|
|
312
|
-
|
|
313
|
-
| Service | Minimum Children |
|
|
314
|
-
|---------|------------------|
|
|
315
|
-
| Workspace | At least 1 child |
|
|
316
|
-
| Lighting | (any) |
|
|
317
|
-
| StarterPlayer | StarterPlayerScripts |
|
|
318
|
-
|
|
319
|
-
### Allowed Empty Services
|
|
320
|
-
|
|
321
|
-
These can be empty for new projects:
|
|
322
|
-
- ReplicatedStorage
|
|
323
|
-
- ServerStorage
|
|
324
|
-
- ServerScriptService
|
|
325
|
-
- StarterGui
|
|
326
|
-
|
|
327
|
-
### Validation Logic
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
function validateSync(): boolean {
|
|
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
|
-
}
|
|
346
|
-
|
|
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");
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Check all required _tree.json files exist
|
|
354
|
-
const required = ["Workspace", "Lighting", "ReplicatedStorage",
|
|
355
|
-
"ServerStorage", "ServerScriptService", "StarterGui", "StarterPlayer"];
|
|
356
|
-
for (const svc of required) {
|
|
357
|
-
if (!fileExists(`${syncDir}/explorer/${svc}/_tree.json`)) {
|
|
358
|
-
errors.push(`Missing ${svc}/_tree.json`);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return errors.length === 0;
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
## Script Sync Details
|
|
369
|
-
|
|
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:
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
const scriptSource = await mcp__robloxstudio__get_script_source({
|
|
389
|
-
path: instance.path
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
const ext = {
|
|
393
|
-
"Script": ".server.luau",
|
|
394
|
-
"LocalScript": ".client.luau",
|
|
395
|
-
"ModuleScript": ".module.luau"
|
|
396
|
-
}[instance.className];
|
|
397
|
-
|
|
398
|
-
Write(`${parentDir}/${instance.name}${ext}`, scriptSource.source);
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
---
|
|
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
|
-
|
|
413
|
-
## Error Handling
|
|
414
|
-
|
|
415
|
-
| Error | Action |
|
|
416
|
-
|-------|--------|
|
|
417
|
-
| MCP not responding | Wait and guide user |
|
|
418
|
-
| Studio not connected | Wait and guide user |
|
|
419
|
-
| Session ID mismatch | Guide user to reconnect plugin |
|
|
420
|
-
| Service sync failed | Retry up to 3 times |
|
|
421
|
-
| Script fetch failed | Log warning, continue |
|
|
422
|
-
| Verification failed | Retry full sync |
|
|
423
|
-
|
|
424
|
-
**Never silently fail. Always report specific errors.**
|
|
425
|
-
|
|
426
|
-
### Session ID Debugging
|
|
427
|
-
|
|
428
|
-
When the user reports "plugin shows connected but sync doesn't work":
|
|
429
|
-
|
|
430
|
-
1. Call `get_connection_info()` and note `server.sessionId` (e.g., "A3F2-B1C7")
|
|
431
|
-
2. Ask user to check plugin UI for "ID: XXXX-XXXX" next to server URL
|
|
432
|
-
3. If IDs don't match:
|
|
433
|
-
- Multiple MCP servers may be running
|
|
434
|
-
- Ask user to disconnect and reconnect the plugin
|
|
435
|
-
- Or restart Claude Code session
|
|
436
|
-
|
|
437
|
-
---
|
|
438
|
-
|
|
439
|
-
## Arguments
|
|
440
|
-
|
|
441
|
-
| Argument | Action |
|
|
442
|
-
|----------|--------|
|
|
443
|
-
| `full` | Execute full sync workflow (Steps 0-7) |
|
|
444
|
-
| `verify` | Run verification only (Step 6) |
|
|
445
|
-
| (none) | Same as `full` |
|
|
446
|
-
|
|
447
|
-
---
|
|
448
|
-
|
|
449
|
-
## Exit Criteria
|
|
450
|
-
|
|
451
|
-
**This skill is NOT complete until ALL conditions are true:**
|
|
452
|
-
|
|
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
|
|
459
|
-
|
|
460
|
-
**If ANY fails, DO NOT return success.**
|
|
461
|
-
|
|
462
|
-
---
|
|
463
|
-
|
|
464
|
-
## Plugin Logs
|
|
465
|
-
|
|
466
|
-
When `enableLogSync` is enabled in plugin settings, logs are synced to the MCP server and saved to:
|
|
467
|
-
|
|
468
|
-
```
|
|
469
|
-
~/.roblox-studio-sync/logs/
|
|
470
|
-
├── current.log # Rolling log (last 500 lines)
|
|
471
|
-
└── plugin-YYYY-MM-DD.log # Daily log files
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
### Log Format
|
|
475
|
-
|
|
476
|
-
```
|
|
477
|
-
[2026-01-29 14:30:45] [INFO] Plugin initialized
|
|
478
|
-
[2026-01-29 14:30:46] [DEBUG] Health check OK - Latency: 15ms
|
|
479
|
-
[2026-01-29 14:31:02] [ERROR] Connection failed: timeout
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
### Log Levels
|
|
483
|
-
|
|
484
|
-
| Level | Description |
|
|
485
|
-
|-------|-------------|
|
|
486
|
-
| DEBUG | Detailed debugging information |
|
|
487
|
-
| INFO | General operational information |
|
|
488
|
-
| WARN | Warning messages for potential issues |
|
|
489
|
-
| ERROR | Error messages for failures |
|
|
490
|
-
| FATAL | Critical errors that may crash the plugin |
|
|
491
|
-
|
|
492
|
-
The `logLevel` setting in the plugin controls the minimum level displayed and synced.
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# =============================================================================
|
|
3
|
-
# verify-sync-complete.sh - Post-sync verification script
|
|
4
|
-
# =============================================================================
|
|
5
|
-
# Verifies the folder-based sync structure is complete and valid.
|
|
6
|
-
# Explorer mirrors Roblox Studio hierarchy with _index.json per folder.
|
|
7
|
-
#
|
|
8
|
-
# Exit codes:
|
|
9
|
-
# 0 = Sync fully verified
|
|
10
|
-
# 1 = Verification failed
|
|
11
|
-
# =============================================================================
|
|
12
|
-
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
SYNC_DIR="${SYNC_DIR:-roblox-project-sync}"
|
|
16
|
-
EXPLORER_DIR="$SYNC_DIR/explorer"
|
|
17
|
-
|
|
18
|
-
# Required service folders
|
|
19
|
-
REQUIRED_SERVICES=("Workspace" "ReplicatedStorage" "ServerScriptService" "StarterPlayer" "StarterGui" "Lighting" "ServerStorage")
|
|
20
|
-
|
|
21
|
-
RED='\033[0;31m'
|
|
22
|
-
GREEN='\033[0;32m'
|
|
23
|
-
YELLOW='\033[1;33m'
|
|
24
|
-
NC='\033[0m'
|
|
25
|
-
|
|
26
|
-
log_success() { echo -e "${GREEN}[PASS]${NC} $1"; }
|
|
27
|
-
log_fail() { echo -e "${RED}[FAIL]${NC} $1"; }
|
|
28
|
-
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
29
|
-
|
|
30
|
-
verify_service() {
|
|
31
|
-
local service="$1"
|
|
32
|
-
local service_dir="$EXPLORER_DIR/$service"
|
|
33
|
-
# Check folder exists
|
|
34
|
-
if [ ! -d "$service_dir" ]; then
|
|
35
|
-
log_fail "$service: Folder not found"
|
|
36
|
-
return 1
|
|
37
|
-
fi
|
|
38
|
-
|
|
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
|
|
44
|
-
if [ ! -f "$index_file" ]; then
|
|
45
|
-
log_fail "$service: _tree.json not found"
|
|
46
|
-
return 1
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# Check file has content
|
|
50
|
-
local size
|
|
51
|
-
size=$(stat -f %z "$index_file" 2>/dev/null || stat -c %s "$index_file" 2>/dev/null || echo "0")
|
|
52
|
-
if [ "$size" -lt 20 ]; then
|
|
53
|
-
log_fail "$service: $(basename $index_file) too small (${size} bytes)"
|
|
54
|
-
return 1
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
# Check JSON has required fields
|
|
58
|
-
if ! grep -q '"name"' "$index_file" 2>/dev/null; then
|
|
59
|
-
log_fail "$service: $(basename $index_file) missing 'name' field"
|
|
60
|
-
return 1
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
if ! grep -q '"className"' "$index_file" 2>/dev/null; then
|
|
64
|
-
log_fail "$service: $(basename $index_file) missing 'className' field"
|
|
65
|
-
return 1
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
# Workspace must have children (Camera, Terrain always exist)
|
|
69
|
-
if [[ "$service" == "Workspace" ]]; then
|
|
70
|
-
local child_count
|
|
71
|
-
child_count=$(grep -o '"childCount":\s*[0-9]*' "$index_file" | grep -o '[0-9]*' || echo "0")
|
|
72
|
-
if [ "$child_count" -lt 2 ]; then
|
|
73
|
-
log_fail "$service: Must have children (childCount: $child_count, expected >= 2)"
|
|
74
|
-
return 1
|
|
75
|
-
fi
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
# Count files in service folder (excluding _index.json)
|
|
79
|
-
local file_count
|
|
80
|
-
file_count=$(find "$service_dir" -type f ! -name '_index.json' 2>/dev/null | wc -l | tr -d ' ')
|
|
81
|
-
|
|
82
|
-
# For services that may be empty (new project), just warn
|
|
83
|
-
if [[ "$service" != "Workspace" && "$service" != "Lighting" && "$service" != "StarterPlayer" ]]; then
|
|
84
|
-
local child_count
|
|
85
|
-
child_count=$(grep -o '"childCount":\s*[0-9]*' "$index_file" | grep -o '[0-9]*' || echo "0")
|
|
86
|
-
if [ "$child_count" -eq 0 ]; then
|
|
87
|
-
log_warn "$service: Empty (childCount: 0) - normal for new project"
|
|
88
|
-
fi
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
log_success "$service: Verified (_index.json: ${size}B, files: ${file_count})"
|
|
92
|
-
return 0
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
main() {
|
|
96
|
-
echo "========================================"
|
|
97
|
-
echo " Post-Sync Verification (Folder Mode)"
|
|
98
|
-
echo "========================================"
|
|
99
|
-
echo ""
|
|
100
|
-
|
|
101
|
-
# Check explorer directory exists
|
|
102
|
-
if [ ! -d "$EXPLORER_DIR" ]; then
|
|
103
|
-
log_fail "Explorer directory not found: $EXPLORER_DIR"
|
|
104
|
-
echo ""
|
|
105
|
-
echo "VERIFICATION=failed"
|
|
106
|
-
echo "REASON=explorer_dir_missing"
|
|
107
|
-
exit 1
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
local failed=0
|
|
111
|
-
local passed=0
|
|
112
|
-
|
|
113
|
-
# Check each required service
|
|
114
|
-
for service in "${REQUIRED_SERVICES[@]}"; do
|
|
115
|
-
if verify_service "$service"; then
|
|
116
|
-
passed=$((passed + 1))
|
|
117
|
-
else
|
|
118
|
-
failed=$((failed + 1))
|
|
119
|
-
fi
|
|
120
|
-
done
|
|
121
|
-
|
|
122
|
-
echo ""
|
|
123
|
-
echo "========================================"
|
|
124
|
-
|
|
125
|
-
# Check timestamp
|
|
126
|
-
if [ -f "$SYNC_DIR/last-sync.txt" ]; then
|
|
127
|
-
local last_sync
|
|
128
|
-
last_sync=$(cat "$SYNC_DIR/last-sync.txt")
|
|
129
|
-
echo "Last sync: $last_sync"
|
|
130
|
-
else
|
|
131
|
-
log_fail "No timestamp found"
|
|
132
|
-
failed=$((failed + 1))
|
|
133
|
-
fi
|
|
134
|
-
|
|
135
|
-
# Count total scripts synced
|
|
136
|
-
local script_count=0
|
|
137
|
-
if [ -d "$EXPLORER_DIR" ]; then
|
|
138
|
-
script_count=$(find "$EXPLORER_DIR" \( -name "*.luau" -o -name "*.lua" \) -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
139
|
-
fi
|
|
140
|
-
echo "Scripts synced: $script_count"
|
|
141
|
-
|
|
142
|
-
# Final result
|
|
143
|
-
echo ""
|
|
144
|
-
if [ "$failed" -eq 0 ]; then
|
|
145
|
-
echo -e "${GREEN}SYNC VERIFIED: $passed/${#REQUIRED_SERVICES[@]} services OK${NC}"
|
|
146
|
-
echo ""
|
|
147
|
-
echo "VERIFICATION=passed"
|
|
148
|
-
echo "SERVICES_OK=$passed"
|
|
149
|
-
echo "SERVICES_TOTAL=${#REQUIRED_SERVICES[@]}"
|
|
150
|
-
echo "SCRIPTS_SYNCED=$script_count"
|
|
151
|
-
exit 0
|
|
152
|
-
else
|
|
153
|
-
echo -e "${RED}SYNC INCOMPLETE: $failed services failed${NC}"
|
|
154
|
-
echo ""
|
|
155
|
-
echo "VERIFICATION=failed"
|
|
156
|
-
echo "SERVICES_FAILED=$failed"
|
|
157
|
-
echo "SERVICES_TOTAL=${#REQUIRED_SERVICES[@]}"
|
|
158
|
-
exit 1
|
|
159
|
-
fi
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
main "$@"
|