@weppy/roblox-mcp 2.10.1 → 2.10.2

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/CHANGELOG.md CHANGED
@@ -16,6 +16,19 @@ All notable changes to this project will be documented in this file.
16
16
 
17
17
 
18
18
 
19
+
20
+ ## [2.10.2] - 2026-07-13
21
+
22
+ ### Features
23
+
24
+ - **Antigravity plugin support** — Antigravity and Antigravity CLI can now load WEPPY's Roblox workflow skills from the shared WEPPY AI Agent Plugin. Antigravity uses the verified skill plugin plus one shared MCP connection, while Antigravity CLI can use the native plugin when its MCP startup is confirmed.
25
+ - **Expanded Roblox workflow skills** — Added dedicated guidance for Asset Library, Creator Store, generated assets, and Studio or Open Cloud uploads. The MCP and Sync skills also cover Multi-Studio routing, UI Studio resources, delete approval and Undo, sourcemaps, and recovery workflows more completely.
26
+
27
+ ### Stability
28
+
29
+ - **Safer Antigravity installs and upgrades** — The installers now keep Antigravity and its CLI on one shared global MCP configuration when needed, migrate older CLI entries without overwriting other servers, and prevent duplicate WEPPY connections. Native plugin failures fall back to the shared MCP setup instead of leaving a partially configured install.
30
+ - **Stronger distribution checks** — Release validation now covers plugin layout, skill references, native and fallback installer modes, legacy configuration migration, Windows and Ubuntu installation, and npm package contents before deployment.
31
+
19
32
  ## [2.10.1] - 2026-07-04
20
33
 
21
34
  ### Bug Fixes
package/README.md CHANGED
@@ -45,7 +45,7 @@ irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1
45
45
  Then reopen your AI app and restart Roblox Studio.
46
46
 
47
47
  Automatic MCP registration supports Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, and Antigravity / Antigravity IDE / Antigravity CLI.
48
- For Claude Code, the installer also tries to add and install the WEPPY Roblox AI Toolkit. For Codex, it adds the WEPPY Roblox AI Toolkit marketplace and then asks you to install WEPPY Roblox AI Toolkit from Plugin Directory.
48
+ For Claude Code, the installer also tries to add and install the WEPPY Roblox AI Toolkit. For Codex, it adds the WEPPY Roblox AI Toolkit marketplace and then asks you to install WEPPY Roblox AI Toolkit from Plugin Directory. For Antigravity, it installs `weppy-roblox-ai-toolkit` where native plugin discovery has been verified and keeps direct registration as the MCP fallback when plugin-scoped MCP is unavailable.
49
49
 
50
50
  ### Browser Web Install
51
51
 
@@ -67,7 +67,7 @@ Supported AI apps are Claude Code, Claude Desktop, Cursor, Codex CLI, Codex App,
67
67
 
68
68
  ### Optional WEPPY Roblox AI Toolkit
69
69
 
70
- Claude Code and Codex can also use the WEPPY Roblox AI Toolkit. The MCP server command above is enough to use WEPPY; the plugin adds client-native setup and workflow guidance.
70
+ Claude Code, Codex, and Antigravity can also use the WEPPY Roblox AI Toolkit. The MCP server command above is enough to use WEPPY; the plugin adds client-native setup and workflow guidance for Studio control, sync, and assets.
71
71
 
72
72
  **Claude Code**
73
73
 
@@ -84,6 +84,12 @@ codex plugin marketplace add hope1026/weppy-roblox-mcp
84
84
 
85
85
  After adding the Codex marketplace, restart Codex, open Plugin Directory, and install **WEPPY Roblox AI Toolkit**.
86
86
 
87
+ **Antigravity**
88
+
89
+ The installer uses `~/.gemini/config/mcp_config.json` as the shared global MCP config. In a CLI-only profile, verified native plugin MCP replaces the shared direct WEPPY entry. When Antigravity IDE and CLI coexist, both plugin views stay skill-only and one shared direct `weppy-roblox-mcp` definition serves both. Outside the verified OS and version matrix, or when native discovery fails, the installer keeps that shared definition as the MCP fallback and asks you to restart and verify.
90
+
91
+ GitHub URLs are not passed directly to `agy plugin install`; the installer downloads the repository archive and installs from a prepared local path.
92
+
87
93
  ## Compatibility
88
94
 
89
95
  | Claude Code | Claude Desktop | Cursor | Codex CLI | Gemini CLI | Antigravity / Antigravity IDE / Antigravity CLI |
package/dist/index.js CHANGED
@@ -501,7 +501,7 @@ Used by: toggle_ui_preview (optional).
501
501
  `)}catch(i){y.warn("Failed to flush change log",{error:i instanceof Error?i.message:String(i),entries:e.length})}}startChangeLogFlusher(){this.flushTimer||(this.flushTimer=setInterval(()=>{this.flushChangeLog(),this.flushHistory()},Afe),this.flushTimer&&typeof this.flushTimer=="object"&&"unref"in this.flushTimer&&this.flushTimer.unref())}async stopChangeLogFlusher(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),await this.flushChangeLog(),await this.flushHistory()}async updateSyncIndex(e,n){this.index.updateBothHashes(e,n)}relativePath(e){return wt.relative(this.config.getSyncRoot(),e)}extractServiceName(e){return Kt(e)[0]??""}findTreeNode(e,n){let i=Kt(n);if(i.length<=1)return null;let r=e.children,a;for(let o=1;o<i.length;o++){if(!r||(a=r.find(s=>s.name===i[o]),!a))return null;r=a.children}return a??null}detachTreeNode(e,n){let i=this.getParentPath(n),r=this.getLeafName(n);if(!i||!r)return null;let a=this.findTreeNode(e,i),o=a?.children??e.children,s=o.findIndex(l=>l.name===r);if(s<0)return null;let[c]=o.splice(s,1);return a?a.childCount=o.length:e.childCount=o.length,c??null}insertTreeNode(e,n,i){let r=this.findTreeNode(e,n);if(r){r.children||(r.children=[]);let o=r.children.findIndex(s=>s.name===i.name);o>=0?r.children[o]=i:r.children.push(i),r.childCount=r.children.length;return}let a=e.children.findIndex(o=>o.name===i.name);a>=0?e.children[a]=i:e.children.push(i),e.childCount=e.children.length}getLeafName(e){let n=Kt(e);return n.length===0?null:n[n.length-1]??null}getParentPath(e){let n=Kt(e);return n.length<=1?null:`game.${n.slice(0,-1).join(".")}`}async copyDirectory(e,n){await this.ensureDir(n);let i=await st.readdir(e,{withFileTypes:!0});for(let r of i){let a=wt.join(e,r.name),o=wt.join(n,r.name);r.isDirectory()?await this.copyDirectory(a,o):await st.copyFile(a,o)}}async tryRename(e,n){try{return this.onWriteCallback?.(e),this.onWriteCallback?.(n),await st.rename(e,n),!0}catch{return!1}}};function IE(t,e){if(t===e)return!0;if(t===null||e===null||typeof t!=typeof e||typeof t!="object")return!1;if(Array.isArray(t))return!Array.isArray(e)||t.length!==e.length?!1:t.every((o,s)=>IE(o,e[s]));let n=t,i=e,r=Object.keys(n),a=Object.keys(i);return r.length!==a.length?!1:r.every(o=>Object.hasOwn(i,o)&&IE(n[o],i[o]))}function Ofe(t,e){let n={},i=new Set([...Object.keys(t??{}),...Object.keys(e)]);for(let r of i){let a=t?.[r]??null,o=e[r]??null;IE(a,o)||(n[r]={before:a,after:o})}return n}Sr();import Ve from"path";import{promises as ts}from"fs";ce();var dx=class{index;placeRoot;constructor(e,n,i){this.index=n,this.placeRoot=i??e.getSyncRoot()}async buildReverseChanges(){let{modified:e,deleted:n}=await this.index.scanForFileModifications(),i=[];for(let a of e){if(this.isForwardOnlyPath(a.fsPath)){this.logForwardOnlySkip(a.fsPath,"buildReverseChanges:modified");continue}try{let o;a.fileType==="script"?o=await this.readModifiedScript(a.fsPath,a.instancePath):a.fileType==="value"?o=await this.readModifiedValue(a.fsPath,a.instancePath):o=await this.readModifiedProps(a.fsPath,a.instancePath),i.push(o)}catch(o){y.warn("Failed to read modified file for reverse sync",{path:a.fsPath,error:o instanceof Error?o.message:String(o)})}}let r=new Set;for(let a of n){if(this.isForwardOnlyPath(a.fsPath)){this.logForwardOnlySkip(a.fsPath,"buildReverseChanges:deleted");continue}if(r.has(a.instancePath))continue;r.add(a.instancePath);let o=Ve.relative(this.placeRoot,a.fsPath);i.push({type:"instanceRemoved",instancePath:a.instancePath,fsPath:o,fileType:a.fileType,content:null,destructive:!0})}return i}async buildChangesFromPending(e){let n=[],i=new Set,r=new Set,a=new Set;for(let o of e)if(o.type==="add"||o.type==="change"){let s=Ve.dirname(o.fsPath),c=this.getFileType(o.fsPath);(c==="props"||c==="script"||c==="value")&&a.add(s)}for(let o of e)try{if(this.isForwardOnlyPath(o.fsPath)){this.logForwardOnlySkip(o.fsPath,`buildChangesFromPending:${o.type}`);continue}if(o.type==="addDir"||o.type==="unlinkDir"){let p=this.resolveInstancePathFromDirectory(o.fsPath);if(!p)continue;let f=this.getSiblingIndexForDirectory(o.fsPath),m=this.buildPendingDedupeKey(p,f);if(o.type==="unlinkDir"){if(i.has(m)||(i.add(m),this.isServiceInstance(p)))continue;let x=Ve.relative(this.placeRoot,o.fsPath),_={type:"instanceRemoved",instancePath:p,fsPath:x,fileType:"directory",content:null,destructive:!0};f&&(_.siblingIndex=f),n.push(_);continue}if(r.has(m)||this.isServiceInstance(p)||a.has(o.fsPath)||!await this.isContainerDirectory(o.fsPath))continue;let h=Ve.relative(this.placeRoot,o.fsPath),v={type:"containerCreated",instancePath:p,fsPath:h,fileType:"directory",content:null,className:"Folder",parentPath:this.extractParentPath(p)};f&&(v.siblingIndex=f),r.add(m),n.push(v);continue}let s=this.resolveInstancePathFromFile(o.fsPath);if(!s)continue;let c=this.getSiblingIndexForFile(o.fsPath);if(o.type==="unlink"){let p=this.buildPendingDedupeKey(s,c);if(i.has(p)||(i.add(p),this.isServiceInstance(s)))continue;let f=Ve.relative(this.placeRoot,o.fsPath),m=this.getFileType(o.fsPath);if(m!=="script"&&m!=="props"&&m!=="value")continue;let g={type:"instanceRemoved",instancePath:s,fsPath:f,fileType:m,content:null,destructive:!0};c&&(g.siblingIndex=c),n.push(g);continue}let l=this.getFileType(o.fsPath),u=!this.index.hasEntry(o.fsPath)&&!this.index.hasInstancePath(s),d;if(u&&o.type==="add"){if(this.isServiceInstance(s))continue;if(l==="script")d=await this.readNewScript(o.fsPath,s);else if(l==="value")d=await this.readNewValue(o.fsPath,s);else if(l==="props")d=await this.readNewInstance(o.fsPath,s);else continue}else if(l==="script")d=await this.readModifiedScript(o.fsPath,s);else if(l==="value")d=await this.readModifiedValue(o.fsPath,s);else if(l==="props")d=await this.readModifiedProps(o.fsPath,s);else continue;c&&(d.siblingIndex=c),n.push(d)}catch(s){y.warn("Failed to build change from pending entry",{path:o.fsPath,type:o.type,error:s instanceof Error?s.message:String(s)})}return n}resolveInstancePathFromFile(e){return this.index.resolveInstancePathFromFsPath(e)}getSiblingIndexForFile(e){let n=this.index.getExplorerRoot();if(Ve.basename(e)==="_tree.json")return;let r=Ve.relative(n,e);if(r.startsWith(".."))return;let a=r.split(Ve.sep).filter(d=>d.length>0);if(a.length<2)return;let o=a[a.length-2],s=Ve.dirname(e),c=Ve.dirname(s),l=this.index.getOriginalInstance(c,o);return l?l.siblingIndex:Gr(o).siblingIndex}isForwardOnlyPath(e){return this.index.isPathUnderClass(e,cl)}logForwardOnlySkip(e,n){y.info("Skipped reverse change for forward-only path",{source:n,path:Ve.relative(this.placeRoot,e),className:this.index.getClassNameForFsPath(e)??"unknown"})}getFileType(e){return this.index.getFileTypeFromPath(e)}resolveInstancePathFromDirectory(e){let n=this.index.getExplorerRoot(),i=Ve.relative(n,e);if(i.startsWith("..")||i===""||Ve.isAbsolute(i))return null;let r=i.split(Ve.sep).filter(s=>s.length>0);if(r.length===0)return null;let a=["game"],o=n;for(let s of r){o=Ve.join(o,s);let c=Ve.dirname(o);a.push(this.index.getOriginalNameForDir(c,s))}return gt(a)}getSiblingIndexForDirectory(e){let n=Ve.basename(e),i=Ve.dirname(e),r=this.index.getOriginalInstance(i,n);return r?r.siblingIndex:Gr(n).siblingIndex}async isContainerDirectory(e){try{let n=await ts.readdir(e,{withFileTypes:!0});for(let i of n)if(i.isFile()&&jb.some(r=>i.name.endsWith(r)))return!1;return!0}catch(n){if(n.code==="ENOENT")return!1;throw n}}buildPendingDedupeKey(e,n){return n?`${e}#${n}`:e}async readModifiedScript(e,n){let i=await ts.readFile(e,"utf-8"),r=Ve.relative(this.placeRoot,e);return{type:"scriptSource",instancePath:n,fsPath:r,fileType:"script",content:i}}async readModifiedProps(e,n){let i=await ts.readFile(e,"utf-8"),r=JSON.parse(i),a=Ve.relative(this.placeRoot,e);return{type:"properties",instancePath:n,fsPath:a,fileType:"props",content:r}}async readModifiedValue(e,n){let i=await ts.readFile(e,"utf-8"),r=JSON.parse(i),a=Ve.relative(this.placeRoot,e);return{type:"valueChanged",instancePath:n,fsPath:a,fileType:"value",content:r}}async readNewScript(e,n){let i=await ts.readFile(e,"utf-8"),r=Ve.relative(this.placeRoot,e),a=Ve.basename(e),o="ModuleScript";a.endsWith(".server.luau")?o="Script":a.endsWith(".client.luau")&&(o="LocalScript");let s=this.extractParentPath(n);return{type:"scriptCreated",instancePath:n,fsPath:r,fileType:"script",content:i,className:o,parentPath:s}}async readNewValue(e,n){let i=await ts.readFile(e,"utf-8"),r=JSON.parse(i),a=Ve.relative(this.placeRoot,e),o=this.extractParentPath(n);return{type:"valueCreated",instancePath:n,fsPath:a,fileType:"value",content:r,className:r.className,parentPath:o}}async readNewInstance(e,n){let i=await ts.readFile(e,"utf-8"),r=JSON.parse(i),a=Ve.relative(this.placeRoot,e),o=this.extractParentPath(n);return{type:"instanceCreated",instancePath:n,fsPath:a,fileType:"props",content:r,className:r.className,parentPath:o}}extractParentPath(e){return St(e)}isServiceInstance(e){let n=Ei(e);return n.length!==2||n[0]!=="game"?!1:JR.has(n[1])}};ce();import Mfe from"path";ce();import qa from"path";import{createHash as F8}from"crypto";import{promises as PE}from"fs";Sr();var Dfe=500,kE=class{explorerRoot;syncIndex;scanIntervalMs;previousSnapshot=new Map;pendingChanges=new Map;scanTimer=null;readyResolvers=[];isReady=!1;isPaused=!1;isScanning=!1;refreshSnapshotOnNextScan=!1;scanEpoch=0;pendingSequence=0;suppressedPaths=new Map;directionChecker=null;onForwardViolation=null;getPendingKey(e,n){return`${qa.resolve(e)}\0${n}`}getPendingSlot(e){return e==="addDir"||e==="unlinkDir"?"dir":"file"}getPendingRank(e){return e==="change"?1:2}isStaleScan(e){return this.isPaused||e!==this.scanEpoch}resolveReadyWaiters(){for(let e of this.readyResolvers)e();this.readyResolvers=[]}queuePendingChange(e){let n=this.getPendingSlot(e.type),i=this.getPendingKey(e.fsPath,n),r=this.getPendingRank(e.type),a=this.pendingChanges.get(i);a&&a.rank>r||this.pendingChanges.set(i,{change:e,rank:r,sequence:++this.pendingSequence})}constructor(e,n,i=Dfe){this.explorerRoot=qa.resolve(e),this.syncIndex=n,this.scanIntervalMs=i}setDirectionChecker(e){this.directionChecker=e}setOnForwardViolation(e){this.onForwardViolation=e}suppressPath(e,n){let i=qa.resolve(e);if(n===void 0){this.suppressedPaths.set(i,{mode:"generic"});return}if(n==="missing"){this.suppressedPaths.set(i,{mode:"missing"});return}this.suppressedPaths.set(i,{mode:"hash",hash:n})}async start(){this.scanTimer&&await this.stop("restart"),y.info("SnapshotChangeScanner: starting",{explorerRoot:this.explorerRoot,scanIntervalMs:this.scanIntervalMs}),this.isPaused=!1,this.refreshSnapshotOnNextScan=!1,this.suppressedPaths.clear(),this.scanEpoch+=1;let e=this.scanEpoch;this.previousSnapshot=await this.syncIndex.buildSnapshotSeed(),!this.isStaleScan(e)&&(this.isReady=!0,this.resolveReadyWaiters(),this.scanTimer=setInterval(()=>{this.scanSnapshotDiffs().catch(n=>{y.warn("SnapshotChangeScanner: background scan failed",{error:n instanceof Error?n.message:String(n)})})},this.scanIntervalMs),typeof this.scanTimer=="object"&&this.scanTimer&&"unref"in this.scanTimer&&this.scanTimer.unref())}async stop(e){y.info("SnapshotChangeScanner: stopping",{reason:e??"unspecified",explorerRoot:this.explorerRoot,isReady:this.isReady,isPaused:this.isPaused,pendingChanges:this.pendingChanges.size}),this.scanTimer&&(clearInterval(this.scanTimer),this.scanTimer=null),this.scanEpoch+=1,this.clearTransientState(),this.previousSnapshot=new Map,this.refreshSnapshotOnNextScan=!1,this.isPaused=!1,this.suppressedPaths.clear(),this.resolveReadyWaiters(),this.isReady=!1,this.isScanning=!1}beginFullSyncReplacement(){this.scanEpoch+=1,this.isPaused=!0,this.isReady=!1,this.refreshSnapshotOnNextScan=!1,this.suppressedPaths.clear(),this.clearTransientState()}async endFullSyncReplacement(){if(this.clearTransientState(),this.scanTimer===null){await this.start();return}let e=++this.scanEpoch;this.isReady=!1,this.finalizeResumedBaseline(e)}isActivelyScanning(){return this.scanTimer!==null&&!this.isPaused}injectPending(e){this.isPaused||(this.queuePendingChange(e),y.debug("SnapshotChangeScanner: injected pending change",{relativePath:e.relativePath,type:e.type}))}drainPendingChanges(){let e=Array.from(this.pendingChanges.values()).sort((n,i)=>n.sequence-i.sequence).map(n=>n.change);return this.pendingChanges.clear(),e}getPendingCount(){return this.pendingChanges.size}getLastDetected(){let e=null;for(let n of this.pendingChanges.values()){let i=n.change;(!e||i.detectedAt>e)&&(e=i.detectedAt)}return e}waitUntilReady(){return this.isReady?Promise.resolve():new Promise(e=>{this.readyResolvers.push(e)})}async rescan(){let e=await this.scanSnapshotDiffs(),n=await this.scanStoredModifications();return e+n}async scanSnapshotDiffs(){if(this.isPaused||this.isScanning)return 0;let e=this.scanEpoch;this.isScanning=!0;try{let n=await this.syncIndex.buildSnapshotSeed();if(this.isStaleScan(e))return 0;if(this.refreshSnapshotOnNextScan)return this.previousSnapshot=n,this.refreshSnapshotOnNextScan=!1,this.suppressedPaths.clear(),0;let i=M8(this.previousSnapshot,n),r=await this.processCandidates(i,e);if(this.isStaleScan(e))return 0;let a=this.commitPendingChanges(r);return this.previousSnapshot=n,this.suppressedPaths.clear(),a>0&&y.info("SnapshotChangeScanner: scan found pending changes",{added:a}),a}finally{this.isScanning=!1}}async scanStoredModifications(){if(this.isPaused)return 0;let e=this.scanEpoch,n=await this.scanStoredModificationsInternal(e);if(!n||this.isStaleScan(e))return 0;for(let i of n.forwardViolations)this.onForwardViolation?.(i);return this.commitPendingChanges(n.pending)}async scanStoredModificationsInternal(e){let n=await this.syncIndex.getModifiedFiles(),i={pending:[],forwardViolations:[]};for(let r of n){if(e!==this.scanEpoch)return null;let a=r.fsPath,o=qa.relative(this.explorerRoot,a);if(await this.isSuppressedPath(a))continue;if(this.shouldRedirectToForwardRestore(o,a)){i.forwardViolations.push(o);continue}let s;switch(r.changeType){case"modified":s="change";break;case"added":s="add";break;case"deleted":s="unlink";break;default:continue}i.pending.push({fsPath:a,relativePath:o,type:s,detectedAt:new Date().toISOString()})}return i}async processCandidates(e,n){let i=[];for(let r of e){if(this.isStaleScan(n))return[];let a=qa.join(this.explorerRoot,r.relativePath),o=new Date().toISOString();if(await this.isSuppressedPath(a)||r.kind==="file"&&wE(r.relativePath))continue;if(this.shouldRedirectToForwardRestore(r.relativePath,a)){this.onForwardViolation?.(r.relativePath);continue}if(r.kind==="dir"){i.push({fsPath:a,relativePath:r.relativePath,type:r.changeType,detectedAt:o});continue}if(r.changeType==="unlink"){i.push({fsPath:a,relativePath:r.relativePath,type:"unlink",detectedAt:o});continue}let s=this.syncIndex.getStoredFileHash(a);try{let c=await PE.readFile(a,"utf-8"),l=F8("md5").update(c,"utf-8").digest("hex");if(s&&l===s){y.debug("SnapshotChangeScanner: echo skipped",{relativePath:r.relativePath,changeType:r.changeType});continue}i.push({fsPath:a,relativePath:r.relativePath,type:r.changeType,detectedAt:o})}catch(c){if(c.code==="ENOENT"){i.push({fsPath:a,relativePath:r.relativePath,type:"unlink",detectedAt:o});continue}y.warn("SnapshotChangeScanner: failed to read candidate file",{path:r.relativePath,changeType:r.changeType,error:c instanceof Error?c.message:String(c)})}}return i}commitPendingChanges(e){let n=0;for(let i of e){let r=this.getPendingSlot(i.type),a=this.getPendingKey(i.fsPath,r),o=this.getPendingRank(i.type),s=this.pendingChanges.get(a);s&&s.rank>o||(s||n++,this.pendingChanges.set(a,{change:i,rank:o,sequence:++this.pendingSequence}))}return n}clearTransientState(){this.pendingChanges.clear()}async finalizeResumedBaseline(e){try{let n=await this.syncIndex.buildSnapshotSeed();if(e!==this.scanEpoch)return;this.previousSnapshot=n,this.refreshSnapshotOnNextScan=!1;let i=await this.scanStoredModificationsInternal(e);if(e!==this.scanEpoch)return;if(i){for(let r of i.forwardViolations)this.onForwardViolation?.(r);this.commitPendingChanges(i.pending)}this.suppressedPaths.clear(),this.isPaused=!1,this.isReady=!0,this.resolveReadyWaiters()}catch(n){if(e!==this.scanEpoch)return;y.warn("SnapshotChangeScanner: resume baseline refresh failed",{error:n instanceof Error?n.message:String(n)}),this.refreshSnapshotOnNextScan=!0,this.isPaused=!1,this.isReady=!0,this.resolveReadyWaiters()}}shouldRedirectToForwardRestore(e,n){return this.syncIndex.isPathUnderClass(n,cl)?!0:this.directionChecker?this.directionChecker(e)==="forward":!1}async isSuppressedPath(e){let n=qa.resolve(e);for(let[i,r]of this.suppressedPaths){if(n===i||n.startsWith(`${i}${qa.sep}`))return r.mode==="generic"?!0:r.mode==="missing"?!await Nfe(n):await jfe(n)===r.hash;if(i.startsWith(`${n}${qa.sep}`))return r.mode==="generic"}return!1}};async function Nfe(t){try{return await PE.access(t),!0}catch{return!1}}async function jfe(t){try{let e=await PE.readFile(t,"utf-8");return F8("md5").update(e,"utf-8").digest("hex")}catch{return null}}var q8=kE;var ut="snapshot-scanner",px=class extends q8{placeId;detectorExplorerRoot;lifecycleGeneration=0;constructor(e,n,i={}){super(e,n,i.scanIntervalMs),this.placeId=i.placeId??null,this.detectorExplorerRoot=Mfe.resolve(e)}async start(){let e=++this.lifecycleGeneration;y.info("Reverse detector bootstrap scheduled",{placeId:this.placeId,mode:ut,explorerRoot:this.detectorExplorerRoot}),await super.start(),e===this.lifecycleGeneration&&y.info("Reverse detector bootstrap completed",{placeId:this.placeId,mode:ut})}async stop(e){this.lifecycleGeneration+=1,y.info("Reverse detector stopping",{placeId:this.placeId,mode:ut,reason:e??"unspecified"}),await super.stop(e)}beginFullSyncReplacement(){y.info("Reverse detector paused for full sync replacement",{placeId:this.placeId,mode:ut}),super.beginFullSyncReplacement()}async endFullSyncReplacement(){y.info("Reverse detector baseline refresh scheduled",{placeId:this.placeId,mode:ut}),await super.endFullSyncReplacement()}async rescan(){y.debug("Reverse detector manual rescan requested",{placeId:this.placeId,mode:ut});let e=await super.rescan();return y.info("Reverse detector manual rescan completed",{placeId:this.placeId,mode:ut,added:e,pendingCount:this.getPendingCount()}),e}};import Il from"path";import{promises as B8}from"fs";function ns(t,e,n,i,r=!1){if(i&&i>=1){let s=St(e);if(s){let c=t.getEffectiveDir(s,i);if(c){let l=lt(e);if(n){let u=t.getResolvedName(e,n);if(u)l=u;else if(r)throw new Error(`Missing collision mapping for ${e}#${n}`)}return RE(t,c,l)}if(r)throw new Error(`Missing parent collision mapping for ${s}#${i}`)}}let a=t.getEffectiveDir(e,n??1);if(a){let s=t.getExplorerRoot(),c=Il.relative(s,a).split(Il.sep).filter(l=>l.length>0);return gt(["game",...c])}let o=e;if(n){let s=t.getResolvedName(e,n);if(s)o=sf(o,s);else if(r)throw new Error(`Missing collision mapping for ${e}#${n}`)}return o}function zfe(t,e){let n=Ei(t),i=Ei(e);if(n.length<=i.length)return!1;for(let r=0;r<i.length;r++)if(n[r]!==i[r])return!1;return!0}function H8(t,e){e=Lfe(t,e);let n=new Map;for(let r=0;r<e.length;r++){let a=e[r];if(a?.type==="instanceRemoved")try{let o=ns(t.index,a.path,a.siblingIndex,a.parentSiblingIndex,!0);n.set(r,o)}catch{continue}}if(n.size<=1)return e;let i=new Set;for(let[r,a]of n)for(let[o,s]of n)if(r!==o&&zfe(a,s)){i.add(r);break}return i.size===0?e:e.filter((r,a)=>!i.has(a))}function Lfe(t,e){let n=new Map;for(let a=0;a<e.length;a++){let o=e[a];if(o?.type!=="instanceRemoved"||o.siblingIndex===void 0)continue;let s=n.get(o.path);s||(s=[],n.set(o.path,s)),s.push(a)}let i=!1;for(let a of n.values()){if(a.length<2)continue;let o=new Set;for(let s of a){let c=e[s].siblingIndex;if(o.has(c)){i=!0;break}o.add(c)}if(i)break}if(!i)return e;let r=[...e];for(let[a,o]of n){if(o.length<2)continue;let s=rs(t.index,a,void 0,!1),c=new Set(t.index.getRegisteredSiblingIndices(a,s));if(c.size===0)continue;let l=new Set;for(let u of o){let d=e[u];if(d.type!=="instanceRemoved")continue;let p=d.siblingIndex;if(!l.has(p)&&c.has(p))l.add(p);else{let f;for(let m of c)if(!l.has(m)){f=m;break}f!==void 0&&(l.add(f),r[u]={...d,siblingIndex:f})}}}return r}function rs(t,e,n,i=!1){if(n&&n>=1){let r=St(e);if(r){let a=t.getEffectiveDir(r,n);if(a)return a;if(i)throw new Error(`Missing parent collision mapping for ${r}#${n}`)}}return t.resolveParentDir(e)}async function Ba(t,e,n,i,r){let a=Il.join(e,n),o=Il.join(e,i);try{(await B8.stat(a)).isDirectory()&&(r&&(r.suppressPath(a),r.suppressPath(o)),await B8.rename(a,o),t.renameHashKeysUnder(a,o),t.renameReverseNameMappingsUnder(a,o),t.renameInstanceDirMappingsUnder(a,o))}catch{return}}function RE(t,e,n){let i=Il.relative(t.getExplorerRoot(),e).split(Il.sep).filter(r=>r.length>0);return gt(["game",...i,n])}async function fx(t,e){let n=t.index.planCollisionReindexAfterBatchRemovals(e.instancePath,[...e.removedSiblingIndices],e.parentDir);for(let i of n.renames)await Ba(t.index,e.parentDir,i.from,i.to,t.fileWatcher),await kl(t.writer,t.index,e.parentDir,i.from,i.to);t.index.applyCollisionReindexAfterBatchRemovals(e.instancePath,e.parentDir,n)}async function kl(t,e,n,i,r){let a=RE(e,n,i),o=RE(e,n,r);await t.renameInTree(a,o,r)}import mx from"path";var Z8=5*60*1e3,V8=100;function EE(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function cf(t){return typeof t=="string"&&t.length>0}function gx(t,e){let n=mx.resolve(t),i=mx.resolve(e),r=mx.relative(n,i);return r===""||!r.startsWith("..")&&!mx.isAbsolute(r)}function lf(t){return t.pluginProcessToken?`process:${t.pluginProcessToken}`:t.pluginSessionId?`session:${t.pluginSessionId}`:t.pluginClientId?`client:${t.pluginClientId}`:null}function W8(t){if(!EE(t))return{success:!1,error:"Body must be an object"};let e=t.phase;if(e!=="start"&&e!=="chunk"&&e!=="complete")return{success:!1,error:`Invalid phase: ${String(e)}`};if(!cf(t.clientId))return{success:!1,error:"clientId is required"};switch(e){case"start":return typeof t.placeId!="number"?{success:!1,error:"placeId must be a number"}:cf(t.placeName)?typeof t.totalServices!="number"?{success:!1,error:"totalServices must be a number"}:typeof t.totalInstances!="number"?{success:!1,error:"totalInstances must be a number"}:t.previousPlaceId!==void 0&&typeof t.previousPlaceId!="number"?{success:!1,error:"previousPlaceId must be a number"}:{success:!0,data:t}:{success:!1,error:"placeName is required"};case"chunk":return cf(t.serviceName)?cf(t.serviceClassName)?Array.isArray(t.instances)?typeof t.chunkIndex!="number"?{success:!1,error:"chunkIndex must be a number"}:typeof t.totalChunks!="number"?{success:!1,error:"totalChunks must be a number"}:{success:!0,data:t}:{success:!1,error:"instances must be an array"}:{success:!1,error:"serviceClassName is required"}:{success:!1,error:"serviceName is required"};case"complete":return typeof t.instanceCount!="number"?{success:!1,error:"instanceCount must be a number"}:typeof t.scriptCount!="number"?{success:!1,error:"scriptCount must be a number"}:{success:!0,data:t}}}function G8(t){if(!EE(t))return{success:!1,error:"Body must be an object"};if(!cf(t.clientId))return{success:!1,error:"clientId is required"};if(t.placeId!==void 0&&typeof t.placeId!="number")return{success:!1,error:"placeId must be a number"};if(typeof t.timestamp!="number")return{success:!1,error:"timestamp must be a number"};if(!Array.isArray(t.changes)||t.changes.length===0)return{success:!1,error:"changes must be a non-empty array"};let e=new Set(["propertyChanged","instanceAdded","instanceRemoved","instanceRenamed","instanceMoved","scriptSourceChanged"]);for(let n=0;n<t.changes.length;n++){let i=t.changes[n];if(!EE(i)||!e.has(i.type))return{success:!1,error:`changes[${n}]: invalid type '${String(i?.type)}'`}}return{success:!0,data:t}}import Ir from"path";import{promises as is}from"fs";Sr();ce();var hx=class{constructor(e){this.ctx=e}async processChangeForPlace(e,n,i){let r=C6(n.type);if(e.directions[r]==="reverse")return y.info("Reverse enforcement: rejecting Studio change on reverse-only path",{placeId:e.placeId,changeType:n.type,dirKey:r,path:"path"in n?n.path:void 0}),(n.type==="scriptSourceChanged"||n.type==="propertyChanged")&&await this.injectLocalAsReverse(e,n),null;switch(n.type){case"propertyChanged":{let o=ns(e.index,n.path,n.siblingIndex,n.parentSiblingIndex,!0),s=await this.checkPropertyConflictForPlace(e,o,n);if(s)return s;let c=n;if(c.attributes!==void 0||c.tags!==void 0){let l=e.index.resolvePropsPath(o),u=await this.buildPropertyChangedPropsData(l,o,n);await e.writer.writeProps(o,u)}else c.properties&&typeof c.properties=="object"&&!Array.isArray(c.properties)?await e.writer.updateProperties(o,c.properties):n.property!==void 0?await e.writer.updateProperty(o,n.property,n.value):y.warn("propertyChanged: missing both property and properties",{path:o});return null}case"instanceAdded":{let o=sl.has(n.className),s=n.path,c=n.name;{let d=rs(e.index,n.path,n.parentSiblingIndex,!0),{resolved:p,retroactiveRename:f}=e.index.registerCollision(n.path,n.siblingIndex,d);f&&(await Ba(e.index,d,f.from,f.to,e.fileWatcher),await kl(e.writer,e.index,d,f.from,f.to));let m=e.index.sanitizeName(n.name);if(p!==m||d!==e.index.resolveParentDir(n.path)){let g=e.index.getExplorerRoot(),h=Ir.relative(g,d).split(Ir.sep).filter(v=>v.length>0);s=gt(["game",...h,p]),c=p}}await e.writer.writeInstance({path:s,name:n.name,className:n.className,properties:n.properties,attributes:n.attributes,tags:n.tags,scriptSource:n.scriptSource,hasChildren:!1,childCount:0,siblingIndex:n.siblingIndex}),this.setOriginalClassMapping(e,n.path,n.className,n.siblingIndex);let l={name:c,className:n.className,childCount:0,...c!==n.name?{originalName:n.name}:{}},u=St(s)||n.parentPath;return await e.writer.addToTree(u,l),e.instanceCount++,o&&n.scriptSource!==void 0&&e.scriptCount++,null}case"instanceRemoved":{let o=ns(e.index,n.path,n.siblingIndex,n.parentSiblingIndex,!0),s=rs(e.index,n.path,n.parentSiblingIndex,!0);y.info("Processing instanceRemoved",{path:o}),await e.writer.removeInstance(o),this.removeOriginalClassMapping(e,n.path,o);let c=lt(o),l=St(o);if(l&&c&&await e.writer.removeFromTree(l,c),n.siblingIndex!==void 0){let d=`${s}\0${n.path}`,p=i.get(d);p||(p={instancePath:n.path,parentDir:s,removedSiblingIndices:new Set},i.set(d,p)),p.removedSiblingIndices.add(n.siblingIndex)}let u=St(o);if(u)try{let d=e.index.resolveChildrenDir(u);Ir.dirname(d)!==e.index.getExplorerRoot()&&(await is.readdir(d)).length===0&&await is.rmdir(d)}catch{return null}return null}case"instanceRenamed":{let o=ns(e.index,n.oldPath,n.siblingIndex,n.parentSiblingIndex,!0),s=St(n.oldPath)===St(n.newPath),c=s?rs(e.index,n.oldPath,n.parentSiblingIndex,!0):null,l=rs(e.index,n.newPath,n.parentSiblingIndex,!0),{resolved:u,retroactiveRename:d}=e.index.registerCollision(n.newPath,n.siblingIndex,l);d&&(await Ba(e.index,l,d.from,d.to,e.fileWatcher),await kl(e.writer,e.index,l,d.from,d.to));let p=u!==e.index.sanitizeName(n.newName)?sf(n.newPath,u):n.newPath;if(await e.writer.renameInstance(o,p,n.newName),this.renameOriginalClassMapping(e,n.oldPath,n.newPath),await e.writer.renameInTree(o,p,u,n.newName),s&&c&&n.siblingIndex!==void 0){let f=e.index.planCollisionReindexAfterRemoval(n.oldPath,n.siblingIndex,c);for(let m of f.renames)await Ba(e.index,c,m.from,m.to,e.fileWatcher),await kl(e.writer,e.index,c,m.from,m.to);e.index.applyCollisionReindexAfterRemoval(n.oldPath,c,f)}return null}case"instanceMoved":{let o=ns(e.index,n.oldPath,n.siblingIndex,n.parentSiblingIndex,!0),s=rs(e.index,n.newPath,n.parentSiblingIndex,!0),{resolved:c,retroactiveRename:l}=e.index.registerCollision(n.newPath,n.siblingIndex,s);l&&(await Ba(e.index,s,l.from,l.to,e.fileWatcher),await kl(e.writer,e.index,s,l.from,l.to));let u=lt(n.newPath)||"",d=c!==e.index.sanitizeName(u)?sf(n.newPath,c):n.newPath;return await e.writer.moveInstance(o,d),this.renameOriginalClassMapping(e,n.oldPath,n.newPath),await e.writer.moveInTree(o,d),null}case"scriptSourceChanged":{let o=ns(e.index,n.path,n.siblingIndex,n.parentSiblingIndex,!0),s=await this.checkScriptConflictForPlace(e,o,n.source);if(s)return s;let c=await this.resolveScriptClassForPlace(e,o);return await this.cleanupStaleScriptFilesForPlace(e,o,c),await e.writer.writeScript(o,c,n.source,!1),null}}}async injectLocalAsReverse(e,n){if(e.fileWatcher)try{if(n.type==="scriptSourceChanged"){let i=await this.resolveScriptClassForPlace(e,n.path),r=e.index.resolveScriptPath(n.path,i,!1),a=Ir.join(this.ctx.config.getPlaceRoot(e.placeId),"explorer"),o=Ir.relative(a,r);e.fileWatcher.injectPending({fsPath:r,relativePath:o,type:"change",detectedAt:new Date().toISOString()})}else if(n.type==="propertyChanged"){let i=e.index.resolvePropsPath(n.path),r=Ir.join(this.ctx.config.getPlaceRoot(e.placeId),"explorer"),a=Ir.relative(r,i);e.fileWatcher.injectPending({fsPath:i,relativePath:a,type:"change",detectedAt:new Date().toISOString()})}}catch(i){y.debug("injectLocalAsReverse: could not inject",{changeType:n.type,error:i instanceof Error?i.message:String(i)})}}async resolveScriptClassForPlace(e,n){try{let i=e.index.resolvePropsPath(n),r=await is.readFile(i,"utf-8"),a=JSON.parse(r);if(a.className&&sl.has(a.className))return a.className}catch{return"ModuleScript"}return"ModuleScript"}async cleanupStaleScriptFilesForPlace(e,n,i){let r=Db[i],a=Ir.join(this.ctx.config.getPlaceRoot(e.placeId),"explorer");for(let[o,s]of Object.entries(Db)){if(s===r)continue;let c=e.index.resolveScriptPath(n,o,!1);try{await is.unlink(c),e.index.removeHash(c),y.info("Cleaned up stale script file",{placeId:e.placeId,removed:Ir.relative(a,c),currentClassName:i})}catch(l){l.code!=="ENOENT"&&y.warn("Failed to clean up stale script file",{path:c,error:l instanceof Error?l.message:String(l)})}}}async checkPropertyConflictForPlace(e,n,i){try{let r=e.index.resolvePropsPath(n),a=e.index.getFileHash(r);if(!a)return null;let o;try{o=await is.readFile(r,"utf-8")}catch{return null}return e.index.computeHash(o)===a?null:{fsPath:Ir.relative(this.ctx.config.getPlaceRoot(e.placeId),r),instancePath:n,fileType:"props",studioContent:await this.buildStudioPropsConflictContent(r,n,i),fileContent:o}}catch{return null}}async checkScriptConflictForPlace(e,n,i){try{let r=await this.resolveScriptClassForPlace(e,n),a=e.index.resolveScriptPath(n,r,!1),o=e.index.getFileHash(a);if(!o)return null;let s;try{s=await is.readFile(a,"utf-8")}catch{return null}return e.index.computeHash(s)===o?null:{fsPath:Ir.relative(this.ctx.config.getPlaceRoot(e.placeId),a),instancePath:n,fileType:"script",studioContent:i,fileContent:s}}catch{return null}}async applyDeferredCollisionBatchReindexForPlace(e,n){await fx(e,n)}async buildStudioPropsConflictContent(e,n,i){let r=await this.buildPropertyChangedPropsData(e,n,i);return JSON.stringify(r,null,2)}async buildPropertyChangedPropsData(e,n,i){let r=null;try{let s=await is.readFile(e,"utf-8");r=JSON.parse(s)}catch{r=null}let a=i.properties?{...i.properties}:{...r?.properties??{}};i.property&&(a[i.property]=i.value);let o={name:r?.name??lt(n)??"",className:i.className??r?.className??"Folder",properties:a};return i.attributes!==void 0?Object.keys(i.attributes).length>0&&(o.attributes={...i.attributes}):r?.attributes&&(o.attributes={...r.attributes}),i.tags!==void 0?i.tags.length>0&&(o.tags=[...i.tags]):r?.tags&&(o.tags=[...r.tags]),o}setOriginalClassMapping(e,n,i,r){e.index.setClassName(n,i,r)}removeOriginalClassMapping(e,n,i){n!==i&&e.index.removeClassMappingsUnderInstancePath(n)}renameOriginalClassMapping(e,n,i){n!==i&&e.index.renameClassMappingKeys(n,i)}};import K8 from"path";import{promises as yx}from"fs";Sr();ce();tr();var vx=class{constructor(e){this.ctx=e}async handlePreCheck(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({hasPreviousSync:!1,changes:[],summary:{modified:0,deleted:0,added:0,total:0}});return}let r=this.ctx.config.getPlaceRoot(i),a=K8.join(r,".sync-index.json"),o=!1;try{await yx.access(a),o=!0}catch{o=!1}if(!o){n.status(200).json({hasPreviousSync:!1,changes:[],summary:{modified:0,deleted:0,added:0,total:0}});return}let s=K8.join(r,"explorer"),c=new Fa(r,s);await c.loadFromDisk();let l=await c.getModifiedFiles(),u=0,d=0,p=0;for(let m of l)switch(m.changeType){case"modified":u++;break;case"deleted":d++;break;case"added":p++;break}let f=l.map(m=>({relPath:m.relPath,instancePath:m.instancePath,changeType:m.changeType,fileType:m.fileType}));n.status(200).json({hasPreviousSync:!0,changes:f,summary:{modified:u,deleted:d,added:p,total:f.length}})}async handleSyncDirections(e,n){let i=e.body,r=i.placeId??this.ctx.getDefaultRuntimePlaceId();if(r==null){n.status(400).json({error:"Missing placeId"});return}let a=this.ctx.places.get(r);if(!a){n.status(404).json({error:"Place not found",message:`No sync context for place ${r}`});return}if(i.directions&&typeof i.directions=="object"){let o=c=>c==="forward"||c==="reverse"||c==="bidirectional",s=i.directions;o(s.scripts)&&(a.directions.scripts=s.scripts),o(s.values)&&(a.directions.values=s.values),o(s.containers)&&(a.directions.containers=s.containers),o(s.data)&&(a.directions.data=s.data),o(s.services)&&(a.directions.services=s.services),y.info("Sync directions updated",{placeId:r,directions:a.directions})}if(i.applyModes&&typeof i.applyModes=="object"){let o=c=>c==="auto"||c==="manual",s=i.applyModes;o(s.scripts)&&(a.applyModes.scripts=s.scripts),o(s.values)&&(a.applyModes.values=s.values),o(s.containers)&&(a.applyModes.containers=s.containers),o(s.data)&&(a.applyModes.data=s.data),o(s.services)&&(a.applyModes.services=s.services)}typeof i.autoApplyDeletes=="boolean"&&(a.autoApplyDeletes=i.autoApplyDeletes),this.ctx.touchRuntimePlace(r),n.status(200).json({status:"updated",directions:a.directions,applyModes:a.applyModes,autoApplyDeletes:a.autoApplyDeletes})}async handleForwardRestoreList(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({paths:[]});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}let a=r.forwardRestoreQueue.splice(0);this.ctx.touchRuntimePlace(i),y.info("Forward restore list drained",{placeId:i,count:a.length}),n.status(200).json({paths:a})}async handleSyncHistory(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({entries:[],total:0,hasMore:!1});return}let r=wn(e.query.limit,50,1,200),a=wn(e.query.offset,0,0),o=e.query.direction,s=e.query.type,c=this.ctx.places.get(i);c&&(await c.writer.flushHistory(),this.ctx.touchRuntimePlace(i));let l=this.ctx.config.getHistoryPath(i),d=(await rf(l,1e4)).reverse().filter(g=>!(o&&g.direction!==o||s&&g.type!==s)),p=d.length,m={entries:d.slice(a,a+r),total:p,hasMore:a+r<p};n.status(200).json(m)}getStatusSummary(){if(this.ctx.activeFullSyncPlaceId!==null&&this.ctx.activeFullSyncPlaceId!==void 0)return{active:!0,placeId:this.ctx.activeFullSyncPlaceId};for(let[e,n]of this.ctx.places.entries())if(n.state==="syncing")return{active:!0,placeId:e};return{active:!1}}getDirectionForCategory(e){let n;if(this.ctx.activeFullSyncPlaceId!==null&&this.ctx.activeFullSyncPlaceId!==void 0&&(n=this.ctx.places.get(this.ctx.activeFullSyncPlaceId)),!n){let r=this.ctx.getDefaultRuntimePlaceId();r!=null&&(n=this.ctx.places.get(r))}if(!n)return"forward";let i=e;return n.directions[i]??"forward"}getStatusDirect(e){let n=e!=null?parseInt(e,10):this.ctx.getDefaultRuntimePlaceId();if(n==null)return{state:"idle",instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,syncRoot:this.ctx.config.getSyncRoot(),activeClientId:null,reverseSyncAvailable:!1,modifiedFileCount:0,applyModes:{...Go},reverseDetectorActive:!1,reverseDetectorMode:ut,fileWatcherActive:!1};let i=this.ctx.places.get(n);if(!i)return{state:"idle",instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,syncRoot:this.ctx.config.getPlaceRoot(n),activeClientId:null,reverseSyncAvailable:!1,modifiedFileCount:0,applyModes:{...Go},reverseDetectorActive:!1,reverseDetectorMode:ut,fileWatcherActive:!1};let r=i.fileWatcher?.getPendingCount()??0,a=i.fileWatcher?.isActivelyScanning()??!1,o=i.fileWatcher!==null;return{state:i.state,instanceCount:i.instanceCount,scriptCount:i.scriptCount,lastFullSync:i.lastFullSync,lastIncrementalSync:i.lastIncrementalSync,syncRoot:this.ctx.config.getPlaceRoot(n),activeClientId:i.activeClientId,reverseSyncAvailable:r>0,modifiedFileCount:r,applyModes:{...i.applyModes},reverseDetectorActive:a,reverseDetectorMode:ut,fileWatcherActive:o}}async getHistoryDirect(e,n){let i=e!=null?parseInt(e,10):this.ctx.getDefaultRuntimePlaceId();if(i==null||!Number.isFinite(i))return{entries:[],total:0,hasMore:!1};let r=this.ctx.places.get(i);r&&await r.writer.flushHistory();let a=Math.min(Math.max(n?.limit??50,1),200),o=Math.max(n?.offset??0,0),s=this.ctx.config.getHistoryPath(i),l=(await rf(s,1e4)).reverse(),u=l.length;return{entries:l.slice(o,o+a),total:u,hasMore:o+a<u}}getDirectionsDirect(e){let n=e!=null?parseInt(e,10):this.ctx.getDefaultRuntimePlaceId();if(n==null)return{...Wo};let i=this.ctx.places.get(n);return i?{...i.directions}:{...Wo}}getProgressDirect(e){let n=e!=null?parseInt(e,10):this.ctx.getDefaultRuntimePlaceId();if(n==null)return{state:"idle",isSyncing:!1};let i=this.ctx.places.get(n);if(!i)return{state:"idle",isSyncing:!1};if(!i.syncProgress)return{state:i.state,isSyncing:!1,lastSync:{instanceCount:i.instanceCount,scriptCount:i.scriptCount,completedAt:i.lastFullSync}};let r=i.syncProgress,a=Date.now()-r.syncStartTime,o=r.totalInstances>0?Math.min(100,Math.round(r.processedInstances/r.totalInstances*100)):0,s;if(r.processedInstances>0&&o<100){let l=a/r.processedInstances,u=r.totalInstances-r.processedInstances;s=Math.round(l*u)}let c=a>0?Math.round(r.bytesReceived/a*1e3):0;return{state:i.state,isSyncing:!0,progressPercent:o,currentService:r.currentService,currentChunk:{index:r.currentChunkIndex,total:r.currentTotalChunks},instances:{processed:r.processedInstances,total:r.totalInstances},services:{processed:r.processedServices,total:r.totalServices},elapsedMs:a,estimatedRemainingMs:s,bytesReceived:r.bytesReceived,bytesPerSecond:c}}async readSyncedFile(e,n){let i=parseInt(e,10),r=this.ctx.places.get(i);if(!r)throw new Error(`Place ${e} is not loaded in the sync cache. Start sync for this place before reading synced files.`);let a=r.index.resolvePropsPath(n);try{return{content:await yx.readFile(a,"utf-8"),path:a}}catch(s){if(s.code!=="ENOENT")throw s}for(let s of sl){let c=r.index.resolveScriptPath(n,s,!1);try{return{content:await yx.readFile(c,"utf-8"),path:c}}catch{continue}}let o=r.index.resolveValuePath(n);try{return{content:await yx.readFile(o,"utf-8"),path:o}}catch(s){if(s.code!=="ENOENT")throw s}throw new Error(`No synced file found for instance: ${n}. Ensure the instance has been synced to disk and that the canonical instance path is correct.`)}async writeSyncedFile(e,n,i){let r=parseInt(e,10),a=this.ctx.places.get(r);if(!a)throw new Error(`Place ${e} is not loaded in the sync cache. Start sync for this place before writing synced files.`);await a.writer.writeScript(n,"Script",i,!1)}async executeViaDisk(e,n){let i=this.ctx.getDefaultRuntimePlaceId();if(i==null)throw new Error("No active sync place for disk execution. Start sync for the current place before using reverse-sync disk execution.");let r=this.ctx.places.get(i);if(!r)throw new Error(`Place ${i} is not loaded in the sync cache. Restart sync before retrying disk execution.`);switch(e){case"manage_scripts_set_source":{let a=n.scriptType||n.className||"Script";return await r.writer.writeScript(n.path,a,n.source,!1),{success:!0,path:n.path}}case"manage_properties_set":return await r.writer.writeProps(n.path,{className:n.className||"Instance",name:lt(n.path),properties:{[n.property]:n.value}}),{success:!0,path:n.path};default:throw new Error(`Disk execution is not supported for command: ${e}. This command must run through the plugin route.`)}}};import Me from"path";import{createHash as Ufe,randomUUID as Ffe}from"crypto";import{promises as jn}from"fs";Sr();Lb();ce();function qfe(t){return Ufe("md5").update(t,"utf-8").digest("hex")}var bx=class{constructor(e){this.ctx=e}preserveLocalFilesMap=new Map;pendingServiceTrees=new Map;async handleInitStart(e,n,i){if(n.previousPlaceId!==void 0&&n.previousPlaceId!==e&&(y.info("Place promotion detected",{from:n.previousPlaceId,to:e}),await this.ctx.config.promotePlaceRoot(n.previousPlaceId,e,n.placeName),this.ctx.places.get(n.previousPlaceId)&&this.ctx.places.delete(n.previousPlaceId),this.ctx.activeFullSyncPlaceId===n.previousPlaceId&&(this.ctx.activeFullSyncPlaceId=null),this.ctx.clearRuntimePlaceIfMatch(n.previousPlaceId)),this.ctx.activeFullSyncPlaceId!==null&&this.ctx.activeFullSyncPlaceId!==void 0&&this.ctx.activeFullSyncPlaceId!==e){i.status(409).json({error:"Conflict",message:`Place ${this.ctx.activeFullSyncPlaceId} is currently syncing. Only one place can sync at a time.`});return}let r=await this.ctx.getOrCreatePlaceContext(e,n.placeName);if(r.activeClientId&&r.activeClientId!==n.clientId&&r.activeFullSyncSessionId!==null){i.status(409).json({error:"Conflict",message:`Another client (${r.activeClientId}) is currently syncing this place`});return}if(this.ctx.activeFullSyncPlaceId=e,this.ctx.touchRuntimePlace(e),r.activeClientId=n.clientId,r.activeSyncIdentityScope=lf(n),r.placeName=n.placeName,n.directions&&typeof n.directions=="object"){let d=n.directions,p=f=>f==="forward"||f==="reverse"||f==="bidirectional";p(d.scripts)&&(r.directions.scripts=d.scripts),p(d.values)&&(r.directions.values=d.values),p(d.containers)&&(r.directions.containers=d.containers),p(d.data)&&(r.directions.data=d.data),p(d.services)&&(r.directions.services=d.services),y.info("Sync directions received",{placeId:e,directions:r.directions})}else r.directions={...Wo};if(n.applyModes&&typeof n.applyModes=="object"){let d=n.applyModes,p=f=>f==="auto"||f==="manual";p(d.scripts)&&(r.applyModes.scripts=d.scripts),p(d.values)&&(r.applyModes.values=d.values),p(d.containers)&&(r.applyModes.containers=d.containers),p(d.data)&&(r.applyModes.data=d.data),p(d.services)&&(r.applyModes.services=d.services)}else r.applyModes={...Go};r.autoApplyDeletes=n.autoApplyDeletes===!0,r.forwardRestoreQueue=[];let a=Ffe();r.activeFullSyncSessionId=a,this.pendingServiceTrees.set(a,new Map),r.syncInitRequestsInFlight=0,r.instanceCount=0,r.scriptCount=0;let o=this.ctx.config.getPlaceRoot(e),s=Me.join(o,`explorer_tmp_${a}`);await jn.mkdir(s,{recursive:!0}),r.tmpIndex=new Fa(o,s),r.tmpWriter=new Cl(this.ctx.config,r.tmpIndex,e),r.collisionDirMap=new Map;let c=n.preserveLocalFiles;Array.isArray(c)&&c.length>0&&(this.setPreserveLocalFiles(a,c),y.info("PreserveLocalFiles set for sync",{syncId:a,fileCount:c.length}));let l={version:1,placeId:n.placeId,placeName:n.placeName,lastFullSync:null,lastIncrementalSync:null,instanceCount:0,scriptCount:0,syncMode:"mirror"},u=Me.join(o,".sync-meta.json");await jn.mkdir(Me.dirname(u),{recursive:!0}),await this.ctx.atomicWriteFile(u,JSON.stringify(l,null,2)+`
502
502
  `),this.startTTLTimerForPlace(r,a),r.state="initializing",r.index.resetNameCounters(),r.syncProgress={syncStartTime:Date.now(),totalInstances:n.totalInstances,totalServices:n.totalServices,processedInstances:0,processedServices:0,currentService:null,currentChunkIndex:0,currentTotalChunks:0,bytesReceived:0,processedChunks:0},r.writer.appendChangeLog(`FULL_SYNC_START clientId=${n.clientId} placeId=${n.placeId}`),r.writer.setBootstrapMode(!0),r.writer.appendHistory({timestamp:new Date().toISOString(),type:"fullSyncStart",direction:"forward",source:"studio",path:`place_${n.placeId}`,details:`services:${n.totalServices} instances:${n.totalInstances}`}),y.info("Full sync started",{syncId:a,clientId:n.clientId,identityScope:r.activeSyncIdentityScope,placeId:n.placeId,placeName:n.placeName,totalServices:n.totalServices,totalInstances:n.totalInstances}),i.status(200).json({status:"started",syncId:r.activeFullSyncSessionId})}async handleInitChunk(e,n,i){let r=this.ctx.places.get(e);if(!r||!r.activeFullSyncSessionId||!r.tmpIndex||!r.tmpWriter){i.status(400).json({error:"No active sync session",message:"Call sync/init with phase=start first"});return}if(r.activeClientId&&n.clientId&&r.activeClientId!==n.clientId){i.status(409).json({error:"Conflict",message:`This sync session belongs to client ${r.activeClientId}`});return}let a=r.activeFullSyncSessionId,o=r.tmpIndex,s=r.tmpWriter;this.startTTLTimerForPlace(r,a),this.beginInitRequest(r);try{let c=this.getOrCreatePendingServiceTree(a,n),l=0,u=r.collisionDirMap;for(let p of n.instances){if(this.ctx.config.isForbiddenPath(p.path))continue;let f=o.resolveParentDir(p.path),m=u.get(f)??f,g=r.activeSyncIdentityScope??lf(n),h=this.getPreferredResolvedName(r,g,p),{resolved:v,retroactiveRename:x}=o.registerCollisionWithPreferredName(p.path,p.siblingIndex??void 0,m,h);x&&(await Ba(o,m,x.from,x.to),this.rewritePendingEffectivePaths(c,o.getExplorerRoot(),Me.join(m,x.from),Me.join(m,x.to)),o.updateSessionDebugMappingResolvedName(g,x.instancePath,x.siblingIndex,x.to));let _=o.resolveChildrenDir(p.path),I=Me.join(m,v);I!==_&&u.set(_,I);let w=o.sanitizeName(p.name),D=p;if(m!==f||v!==w){let G=o.getExplorerRoot(),K=Me.relative(G,m).split(Me.sep).filter(ht=>ht.length>0),Ce=gt(["game",...K,v]);D={...p,path:Ce}}let M=await s.writeInstance(D);o.setClassName(p.path,p.className,p.siblingIndex),this.recordSessionDebugMapping(r,g,p,v),l++,(M.propsWritten||M.valueWritten)&&r.instanceCount++,M.scriptWritten&&r.scriptCount++,c.instances.push({effectivePath:D.path,originalPath:p.path,className:p.className})}let d=this.isLastChunk(c,n.chunkIndex,n.totalChunks);if(d){let p=this.buildServiceTree(r,c);await s.writeTree(n.serviceName,p);let f=this.pendingServiceTrees.get(a);f?.delete(n.serviceName),f&&f.size===0&&this.pendingServiceTrees.delete(a)}r.syncProgress&&(r.syncProgress.processedInstances+=l,r.syncProgress.currentService=n.serviceName,r.syncProgress.currentChunkIndex=n.chunkIndex,r.syncProgress.currentTotalChunks=n.totalChunks,r.syncProgress.processedChunks++,r.syncProgress.bytesReceived+=JSON.stringify(n).length,d&&r.syncProgress.processedServices++),y.debug("Sync chunk processed",{placeId:e,serviceName:n.serviceName,chunkIndex:n.chunkIndex,totalChunks:n.totalChunks,processed:l}),i.status(200).json({processed:l,service:n.serviceName})}finally{this.endInitRequest(r)}}async handleInitComplete(e,n,i){let r=this.ctx.places.get(e);if(!r||!r.activeFullSyncSessionId){i.status(400).json({error:"No active sync session",message:"Call sync/init with phase=start first"});return}if(r.activeClientId&&n.clientId&&r.activeClientId!==n.clientId){i.status(409).json({error:"Conflict",message:`This sync session belongs to client ${r.activeClientId}`});return}let a=r.activeFullSyncSessionId;this.startTTLTimerForPlace(r,a),this.beginInitRequest(r);let o=this.ctx.config.getPlaceRoot(e),s=Me.join(o,"explorer"),c=Me.join(o,`explorer_tmp_${a}`),l=r.fileWatcher,u=this.getAndClearPreserveLocalFiles(a),d=new Map,p=[];if(u.length>0){for(let f of u){let m=Me.resolve(o,f);try{let g=await jn.readFile(m,"utf-8");d.set(f,g)}catch{p.push(f)}}y.info("Backed up local files for preservation",{placeId:e,requested:u.length,backed:d.size,deleted:p.length})}l&&l.beginFullSyncReplacement();try{try{await jn.rm(s,{recursive:!0,force:!0})}catch{}await jn.rename(c,s),r.instanceCount=n.instanceCount,r.scriptCount=n.scriptCount,r.lastFullSync=new Date().toISOString();let f={version:1,placeId:r.placeId,placeName:r.placeName,lastFullSync:r.lastFullSync,lastIncrementalSync:r.lastIncrementalSync,instanceCount:r.instanceCount,scriptCount:r.scriptCount,syncMode:"mirror"},m=Me.join(o,".sync-meta.json");if(await this.ctx.atomicWriteFile(m,JSON.stringify(f,null,2)+`
503
503
  `),this.clearTTLTimerForPlace(r,a),r.index.clearAllHashes(),r.index.clearClassMappings(),r.tmpIndex){let g=r.tmpIndex.getExplorerRoot(),h=r.index.getExplorerRoot();for(let[v,x]of r.tmpIndex.getAllHashes()){let _=Me.relative(g,v),I=Me.resolve(h,_);r.index.updateHashByValue(I,x)}for(let[v,x]of r.tmpIndex.getAllFileHashes()){let _=Me.relative(g,v),I=Me.resolve(h,_);r.index.updateFileHashByValue(I,x)}r.index.resetNameCounters(),r.index.mergeNameMappingsFrom(r.tmpIndex),r.index.mergeSessionDebugMappingsFrom(r.tmpIndex)}if(r.tmpIndex=null,r.tmpWriter&&(r.tmpWriter.stopChangeLogFlusher(),r.tmpWriter=null),this.pendingServiceTrees.delete(a),r.collisionDirMap=null,r.activeSyncIdentityScope=null,await r.index.saveToDisk(),r.state="syncing",r.activeFullSyncSessionId=null,r.syncProgress=null,this.ctx.touchRuntimePlace(e),this.ctx.activeFullSyncPlaceId=null,d.size>0){for(let[g,h]of d){let v=Me.resolve(o,g);try{await jn.mkdir(Me.dirname(v),{recursive:!0}),await jn.writeFile(v,h,"utf-8"),l?.suppressPath(v,qfe(h))}catch(x){y.warn("Failed to restore preserved file",{path:g,error:x instanceof Error?x.message:String(x)})}}y.info("Restored preserved local files",{placeId:e,count:d.size})}if(p.length>0){let g=0;for(let h of p){let v=Me.resolve(o,h);try{await jn.unlink(v),r.index.removeHash(v),l?.suppressPath(v,"missing"),g++}catch(x){x.code!=="ENOENT"&&y.warn("Failed to delete preserved-as-deleted file",{path:h,error:x instanceof Error?x.message:String(x)})}}g>0&&(await r.index.saveToDisk(),y.info("Deleted locally-removed files from new sync",{placeId:e,count:g}))}try{let g=this.ctx.config.getSyncRoot();await zb(g,o)}catch(g){y.warn("Failed to generate place sourcemap after full sync",{placeId:e,error:g instanceof Error?g.message:String(g)})}try{let g=this.ctx.config.getSyncRoot(),h={version:1,lastActivePlaceId:r.placeId,lastActivePlaceName:r.placeName??null,lastActiveAt:new Date().toISOString()},v=Me.join(g,".project-meta.json");await this.ctx.atomicWriteFile(v,JSON.stringify(h,null,2)+`
504
- `),await ll(g)}catch(g){y.warn("Failed to refresh root representative sourcemap after full sync",{placeId:e,error:g instanceof Error?g.message:String(g)})}this.ctx.startFileWatcherForPlace(r).catch(g=>{y.warn("Failed to start reverse detector after full sync",{placeId:e,error:g instanceof Error?g.message:String(g)}),r.fileWatcher=null}),r.writer.setBootstrapMode(!1),r.writer.appendChangeLog(`FULL_SYNC_COMPLETE instances=${r.instanceCount} scripts=${r.scriptCount}`),r.writer.appendHistory({timestamp:new Date().toISOString(),type:"fullSyncComplete",direction:"forward",source:"studio",path:`place_${e}`,details:`instances:${r.instanceCount} scripts:${r.scriptCount}`}),y.info("Full sync completed",{placeId:e,instanceCount:r.instanceCount,scriptCount:r.scriptCount}),i.status(200).json({status:"completed",instanceCount:r.instanceCount,scriptCount:r.scriptCount,syncRoot:this.ctx.config.getPlaceRoot(e)})}catch(f){throw l&&l.endFullSyncReplacement(),f}finally{this.endInitRequest(r)}}setPreserveLocalFiles(e,n){this.preserveLocalFilesMap.set(e,n)}getAndClearPreserveLocalFiles(e){let n=this.preserveLocalFilesMap.get(e)||[];return this.preserveLocalFilesMap.delete(e),n}clearPreserveLocalFiles(e){this.preserveLocalFilesMap.delete(e)}clearPendingServiceTrees(e){this.pendingServiceTrees.delete(e)}startTTLTimerForPlace(e,n){e.incompleteSyncTimer&&(clearTimeout(e.incompleteSyncTimer),e.incompleteSyncTimer=null);let i=setTimeout(async()=>{if(y.warn("Incomplete sync TTL expired, cleaning up",{placeId:e.placeId,syncId:n}),e.incompleteSyncTimer=null,e.activeFullSyncSessionId===n&&e.syncInitRequestsInFlight>0){y.warn("Incomplete sync TTL expired while sync init request is in flight, extending cleanup",{placeId:e.placeId,syncId:n,syncInitRequestsInFlight:e.syncInitRequestsInFlight}),this.startTTLTimerForPlace(e,n);return}let r=this.ctx.config.getPlaceRoot(e.placeId),a=Me.join(r,`explorer_tmp_${n}`);try{await jn.rm(a,{recursive:!0,force:!0})}catch(o){y.error("Failed to clean up expired temp dir",o instanceof Error?o:new Error(String(o)))}e.activeFullSyncSessionId===n&&(e.activeFullSyncSessionId=null,e.activeClientId=null,e.state="idle",e.tmpIndex=null,e.syncInitRequestsInFlight=0,this.pendingServiceTrees.delete(n),e.collisionDirMap=null,e.activeSyncIdentityScope=null,e.tmpWriter&&(e.tmpWriter.stopChangeLogFlusher(),e.tmpWriter=null),this.ctx.activeFullSyncPlaceId===e.placeId&&(this.ctx.activeFullSyncPlaceId=null),this.ctx.clearRuntimePlaceIfMatch(e.placeId))},Z8);i&&typeof i=="object"&&"unref"in i&&i.unref(),e.incompleteSyncTimer=i}getOrCreatePendingServiceTree(e,n){let i=this.pendingServiceTrees.get(e);i||(i=new Map,this.pendingServiceTrees.set(e,i));let r=i.get(n.serviceName);if(r)return r;let a={serviceName:n.tree?.name??n.serviceName,serviceClassName:n.tree?.className??n.serviceClassName,zeroBasedChunkIndex:n.chunkIndex===0,instances:[]};return i.set(n.serviceName,a),a}isLastChunk(e,n,i){return i<=1?!0:e.zeroBasedChunkIndex?n>=i-1:n>=i}getPreferredResolvedName(e,n,i){let r=typeof i.sessionDebugId=="string"?i.sessionDebugId:"";if(!n||r==="")return;let a=e.index.getSessionDebugMapping(n,r);if(!a)return;let o=St(i.path),s=lt(i.path)||i.name;if(!(a.parentPath!==o||a.originalName!==s))return a.resolvedName}recordSessionDebugMapping(e,n,i,r){let a=typeof i.sessionDebugId=="string"?i.sessionDebugId:"";!n||a===""||!e.tmpIndex||e.tmpIndex.setSessionDebugMapping({scope:n,sessionDebugId:a,instancePath:i.path,parentPath:St(i.path),originalName:lt(i.path)||i.name,siblingIndex:Math.max(1,i.siblingIndex??1),resolvedName:r,className:i.className,updatedAt:new Date().toISOString()})}buildServiceTree(e,n){let i={name:n.serviceName,className:n.serviceClassName,childCount:0,children:[],syncedAt:new Date().toISOString()};for(let r of n.instances){let a=this.resolveEffectiveSegments(e,r.effectivePath),o=Kt(r.originalPath);this.upsertTreeNode(i,a,o,r.className)}return this.recomputeTreeChildCounts(i),i.syncedAt=new Date().toISOString(),i}resolveEffectiveSegments(e,n){return e.tmpIndex?Kt(n).map(i=>e.tmpIndex.sanitizeName(i)):Kt(n)}rewritePendingEffectivePaths(e,n,i,r){let a=Me.relative(n,i).split(Me.sep).filter(l=>l.length>0),o=Me.relative(n,r).split(Me.sep).filter(l=>l.length>0);if(a.length===0||o.length===0)return;let s=gt(["game",...a]),c=gt(["game",...o]);for(let l of e.instances){if(l.effectivePath===s){l.effectivePath=c;continue}(l.effectivePath.startsWith(`${s}.`)||l.effectivePath.startsWith(`${s}[`))&&(l.effectivePath=`${c}${l.effectivePath.slice(s.length)}`)}}upsertTreeNode(e,n,i,r){if(n.length<=1)return;let a=e.children;for(let o=1;o<n.length;o++){let s=n[o],c=i[o],l=o===n.length-1,u=a.find(d=>d.name===s);u?l&&(u.className=r,c!==void 0&&c!==s&&(u.originalName=c)):(u={name:s,className:l?r:"Folder",childCount:0,children:[]},c!==void 0&&c!==s&&(u.originalName=c),a.push(u)),u.children||(u.children=[]),a=u.children}}recomputeTreeChildCounts(e){let n=i=>{let r=i.children??[];i.children=r;for(let a of r)n(a);i.childCount=r.length};for(let i of e.children)n(i);e.childCount=e.children.length}clearTTLTimerForPlace(e,n){e.incompleteSyncTimer&&e.activeFullSyncSessionId===n&&(clearTimeout(e.incompleteSyncTimer),e.incompleteSyncTimer=null)}beginInitRequest(e){e.syncInitRequestsInFlight++}endInitRequest(e){e.syncInitRequestsInFlight=Math.max(0,e.syncInitRequestsInFlight-1)}async cleanupStaleTempDirs(){let e=this.ctx.config.getSyncRoot();try{let n=await jn.readdir(e,{withFileTypes:!0});for(let i of n)if(i.isDirectory()){if(i.name.startsWith("explorer_tmp_")){let r=Me.join(e,i.name);y.warn("Removing stale temp directory from crashed sync",{dir:i.name});try{await jn.rm(r,{recursive:!0,force:!0})}catch(a){y.error(`Failed to remove stale temp dir: ${i.name}`,a instanceof Error?a:new Error(String(a)))}}if(i.name.startsWith("place_")){let r=Me.join(e,i.name);try{let a=await jn.readdir(r,{withFileTypes:!0});for(let o of a)if(o.isDirectory()&&o.name.startsWith("explorer_tmp_")){let s=Me.join(r,o.name);y.warn("Removing stale temp directory from crashed sync",{dir:`${i.name}/${o.name}`});try{await jn.rm(s,{recursive:!0,force:!0})}catch(c){y.error(`Failed to remove stale temp dir: ${i.name}/${o.name}`,c instanceof Error?c:new Error(String(c)))}}}catch{continue}}}}catch(n){if(n.code==="ENOENT")return;y.warn("Failed to scan for stale temp dirs",{error:n instanceof Error?n.message:String(n)})}}};import kr from"path";import{promises as xx}from"fs";Sr();ce();var _x=class{constructor(e){this.ctx=e}async handleReversePending(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({pending:0,hasConflicts:!1,lastDetected:null});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}let a={pending:r.fileWatcher?.getPendingCount()??0,hasConflicts:!1,lastDetected:r.fileWatcher?.getLastDetected()??null,forwardRestoreNeeded:r.forwardRestoreQueue.length};this.ctx.touchRuntimePlace(i),n.status(200).json(a)}async handleReverseSyncChanges(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({changes:[],count:0});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}if(r.state!=="syncing"){n.status(400).json({error:"Not syncing",message:"Reverse sync is only available when sync is active"});return}let a=r.fileWatcher?.drainPendingChanges()??[],o=a.length>0?await r.reader.buildChangesFromPending(a):[];this.ctx.touchRuntimePlace(i),n.status(200).json({changes:o,count:o.length})}async handleReverseSyncResult(e,n){let i=e.body,r=i.placeId??this.ctx.getDefaultRuntimePlaceId();if(r==null){n.status(400).json({error:"Validation error",message:"placeId is required (in body or via active sync session)"});return}let a=i.appliedFiles??i.appliedPaths;if(!a||!Array.isArray(a)){n.status(400).json({error:"Validation error",message:"appliedFiles (or appliedPaths) must be an array of relative file paths"});return}let o=this.ctx.places.get(r);if(!o){n.status(404).json({error:"Place not found",message:`No sync context for place ${r}`});return}this.ctx.touchRuntimePlace(r);let s=this.ctx.config.getPlaceRoot(r),c=0,l=[];for(let u of a){let d=kr.resolve(s,u);if(!gx(s,d)){l.push({path:u,error:"Path is outside the place root"});continue}try{let p=await xx.readFile(d,"utf-8"),f=o.index.computeHash(p);o.index.updateHashByValue(d,f),o.index.updateFileHashByValue(d,f),c++}catch(p){let f=p.code;if(f==="ENOENT"){o.index.removeHash(d),o.index.removeHashesUnder(d);let m=this.resolveInstancePathForAppliedPath(o.index,d);if(m){let g=lt(m),h=St(m);h&&g&&await o.writer.removeFromTree(h,g)}c++}else f==="EISDIR"?c++:l.push({path:u,error:p instanceof Error?p.message:String(p)})}}c>0&&await o.index.saveToDisk(),c>0&&o.writer.appendHistory({timestamp:new Date().toISOString(),type:"reverseApply",direction:"reverse",source:"local",path:`place_${r}`,details:`applied:${c} failed:${l.length}`}),n.status(200).json({updated:c,failed:l.length,errors:l})}async handleResolveConflict(e,n){let i=e.body;if(!i.fsPath||!i.resolution){n.status(400).json({error:"Validation error",message:"fsPath and resolution are required"});return}let{fsPath:r,resolution:a}=i,o=this.ctx.config.getSyncRoot();if(!gx(o,kr.resolve(o,r))){n.status(403).json({error:"Forbidden",message:"Path is outside the sync root"});return}if(a==="skip"){n.status(200).json({status:"skipped",fsPath:r});return}let s;if(i.placeId&&(s=this.ctx.places.get(i.placeId)),!s){let p=r.match(/^place_(\d+)(?:_[^/]+)?\//);if(p){let f=parseInt(p[1],10);s=this.ctx.places.get(f)}else s=Array.from(this.ctx.places.values())[0]}if(!s){n.status(404).json({error:"No active place context",message:"No sync session is active. Start a sync first."});return}let c=this.ctx.config.getPlaceRoot(s.placeId),l=kr.resolve(c,r);if(!gx(c,l)){n.status(403).json({error:"Forbidden",message:"Path is outside the place root"});return}let u=s.index,d=s.reader;if(a==="apply-studio"){if(typeof i.studioContent!="string"){n.status(400).json({error:"Validation error",message:"studioContent is required for apply-studio resolution"});return}await xx.mkdir(kr.dirname(l),{recursive:!0});let p=i.studioContent,f=u.computeHash(p);s.fileWatcher?.suppressPath(l,f),await xx.writeFile(l,p,"utf-8"),u.updateHashByValue(l,f),u.updateFileHashByValue(l,f),await u.saveToDisk(),n.status(200).json({status:"resolved",resolution:"apply-studio",fsPath:r});return}if(a==="apply-file"){let p=await xx.readFile(l,"utf-8"),f=u.computeHash(p);u.resolveFile(l,"apply-file",f),await u.saveToDisk();let m=d.getFileType(l),g=d.resolveInstancePathFromFile(l);n.status(200).json({status:"resolved",resolution:"apply-file",fsPath:r,instancePath:g,fileType:m,content:p});return}n.status(400).json({error:"Invalid resolution",message:`Unknown resolution: ${a}`})}async handleReverseRescan(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({added:0});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}if(!r.fileWatcher){n.status(200).json({added:0});return}let a=await r.fileWatcher.rescan();this.ctx.touchRuntimePlace(i),y.info("Reverse rescan completed",{placeId:i,added:a}),n.status(200).json({added:a})}resolveInstancePathForAppliedPath(e,n){let i=e.resolveInstancePathFromFsPath(n);if(i)return i;let r=e.getExplorerRoot(),a=kr.relative(r,n);if(a.startsWith("..")||a===""||kr.isAbsolute(a))return null;let o=a.split(kr.sep).filter(f=>f.length>0);if(o.length<2)return null;let s=kr.basename(n),c=kr.dirname(n),l=e.getOriginalInstance(c,s);if(l)return l.instancePath;let u=s.toLowerCase();if(jb.some(f=>u.endsWith(f))||u==="_tree.json")return null;let d=["game"],p=r;for(let f of o){p=kr.join(p,f);let m=kr.dirname(p);d.push(e.getOriginalNameForDir(m,f))}return gt(d)}};Sr();Lb();ce();var Hfe=5;function J8(t){if(!t||typeof t!="object")return;let e=t;if(Array.isArray(e.instances))for(let n of e.instances)Array.isArray(n.properties)&&n.properties.length===0&&(n.properties={}),Array.isArray(n.attributes)&&n.attributes.length===0&&(n.attributes={});if(Array.isArray(e.changes))for(let n of e.changes)Array.isArray(n.properties)&&n.properties.length===0&&(n.properties={}),Array.isArray(n.attributes)&&n.attributes.length===0&&(n.attributes={})}function Zfe(t){return t.type==="instanceAdded"||t.type==="instanceRemoved"||t.type==="instanceRenamed"||t.type==="instanceMoved"||t.type==="scriptSourceChanged"}var Kr=class{config;places;apiHandler;changeProcessor;initHandler;reverseHandler;reverseDetectorFactory;activeFullSyncPlaceId=null;activeRuntimeSyncPlaceId=null;currentConnectedPlaceId=null;currentConnectedPlaceName=null;constructor(e,n={}){this.config=new $b(e,n),this.reverseDetectorFactory=n.reverseDetectorFactory??(i=>new px(i.explorerRoot,i.syncIndex,{placeId:i.placeId})),this.apiHandler=new vx(this),this.changeProcessor=new hx(this),this.initHandler=new bx(this),this.reverseHandler=new _x(this),this.places=new ux({max:Hfe,dispose:(i,r)=>{y.info("Disposing place context (LRU eviction)",{placeId:r}),this.activeFullSyncPlaceId===r&&(this.activeFullSyncPlaceId=null),i.fileWatcher&&(y.info("Disposing place context: stopping reverse detector",{placeId:r,reason:"lru-dispose",mode:ut}),i.fileWatcher.stop("lru-dispose").catch(a=>{y.error("Error stopping reverse detector during dispose",a)}),i.fileWatcher=null),i.writer.stopChangeLogFlusher().catch(a=>{y.error("LRU dispose \uC911 changelog flush \uC2E4\uD328",a)}),i.incompleteSyncTimer&&(clearTimeout(i.incompleteSyncTimer),i.incompleteSyncTimer=null),i.index.clearAllMaps(),i.index.saveToDisk().catch(a=>{y.error("Error saving index during dispose",a)}),i.activeFullSyncSessionId&&this.initHandler.clearPendingServiceTrees(i.activeFullSyncSessionId),i.tmpWriter&&(i.tmpWriter.stopChangeLogFlusher(),i.tmpWriter=null),i.tmpIndex=null,i.collisionDirMap=null,i.activeSyncIdentityScope=null,i.syncInitRequestsInFlight=0}})}getSyncRoot(){return this.config.getSyncRoot()}async getOrCreatePlaceContext(e,n){let i=this.places.get(e);if(i&&n){let r=this.config.getPlaceRoot(e),a=await this.config.resolvePlaceRoot(e,n);a!==r&&(y.info("Place root migrated, recreating context",{placeId:e,from:r,to:a}),this.places.delete(e),i=void 0)}if(!i){let r=await this.config.resolvePlaceRoot(e,n),a=TE.join(r,"explorer");await Pl.mkdir(r,{recursive:!0}),await Pl.mkdir(a,{recursive:!0});let o=new Fa(r,a);await o.loadFromDisk();let s=new Cl(this.config,o,e),c=new dx(this.config,o,r);s.startChangeLogFlusher(),i={placeId:e,placeName:"",index:o,writer:s,reader:c,fileWatcher:null,state:"idle",activeClientId:null,activeFullSyncSessionId:null,instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,tmpIndex:null,tmpWriter:null,incompleteSyncTimer:null,syncInitRequestsInFlight:0,changesSinceLastSave:0,directions:{...Wo},applyModes:{...Go},autoApplyDeletes:!1,forwardRestoreQueue:[],syncProgress:null,collisionDirMap:null,activeSyncIdentityScope:null},this.places.set(e,i),y.info("Created new place context",{placeId:e,placeRoot:r})}return i}async handleSyncInit(e,n){try{J8(e.body);let i=W8(e.body);if(!i.success){n.status(400).json({error:"Validation error",message:i.error});return}let r=i.data,a=r.phase==="start"?r.placeId??null:r.phase==="chunk"||r.phase==="complete"?this.activeFullSyncPlaceId:null;if(a==null){n.status(400).json({error:"Missing placeId",message:"placeId is required in start phase or must be set by previous start"});return}switch(r.phase){case"start":this.setCurrentConnectedPlace(a,r.placeName),await this.initHandler.handleInitStart(a,r,n);break;case"chunk":await this.initHandler.handleInitChunk(a,r,n);break;case"complete":await this.initHandler.handleInitComplete(a,r,n);break}}catch(i){this.sendError(n,i,"handleSyncInit")}}async handleSyncUpdate(e,n){try{J8(e.body);let i=G8(e.body);if(!i.success){n.status(400).json({error:"Validation error",message:i.error});return}let r=i.data,a=r.placeId??this.getDefaultRuntimePlaceId();if(a==null){n.status(400).json({error:"Missing placeId",message:"placeId is required in body or must have an active sync session"});return}let o=await this.getOrCreatePlaceContext(a);if(this.setCurrentConnectedPlace(a,o.placeName||this.currentConnectedPlaceName),o.activeFullSyncSessionId!==null||o.state==="initializing"){n.status(409).json({error:"Conflict",message:`Full sync in progress for place ${a}`});return}o.activeClientId=r.clientId,this.touchRuntimePlace(a);let s=H8(o,r.changes);y.info("Sync update received",{placeId:a,clientId:r.clientId,changeCount:s.length,receivedCount:r.changes.length,types:s.map(m=>m.type)});let c=[],l=[],u=0,d=!1,p=new Map;for(let m of s)try{let g=await this.changeProcessor.processChangeForPlace(o,m,p);g?l.push(g):(u++,Zfe(m)&&(d=!0))}catch(g){let h="path"in m?m.path:"oldPath"in m?m.oldPath:"unknown";c.push({path:h,error:g instanceof Error?g.message:String(g)})}for(let m of p.values())try{await fx(o,m)}catch(g){c.push({path:m.instancePath,error:g instanceof Error?g.message:String(g)})}if(d)try{let m=this.config.getSyncRoot(),g=this.config.getPlaceRoot(a);await zb(m,g),await ll(m)}catch(m){y.warn("Failed to refresh sourcemaps after incremental sync update",{placeId:a,error:m instanceof Error?m.message:String(m)})}o.changesSinceLastSave+=u,o.changesSinceLastSave>=V8&&(await o.index.saveToDisk(),o.changesSinceLastSave=0),o.lastIncrementalSync=new Date().toISOString();let f={processed:u,failed:c.length,errors:c,syncedAt:o.lastIncrementalSync};l.length>0&&(f.conflicts=l),n.status(200).json(f)}catch(i){this.sendError(n,i,"handleSyncUpdate")}}getDefaultRuntimePlaceId(){return this.currentConnectedPlaceId}getDefaultRuntimePlaceName(){if(this.currentConnectedPlaceName)return this.currentConnectedPlaceName;if(this.currentConnectedPlaceId!==null&&this.currentConnectedPlaceId!==void 0){let e=this.places.get(this.currentConnectedPlaceId);if(e?.placeName)return e.placeName}return null}setCurrentConnectedPlace(e,n){if(this.currentConnectedPlaceId=e,e==null){this.currentConnectedPlaceName=null;return}if(typeof n=="string"&&n.length>0){this.currentConnectedPlaceName=n;let r=this.places.get(e);r&&(r.placeName=n);return}let i=this.places.get(e);i?.placeName&&(this.currentConnectedPlaceName=i.placeName)}clearCurrentConnectedPlaceIfMatch(e){this.currentConnectedPlaceId===e&&(this.currentConnectedPlaceId=null,this.currentConnectedPlaceName=null)}touchRuntimePlace(e){this.activeRuntimeSyncPlaceId=e}clearRuntimePlaceIfMatch(e){this.activeRuntimeSyncPlaceId===e&&(this.activeRuntimeSyncPlaceId=null)}resolveQueryPlaceId(e,n="runtime"){let i=e.query.placeId;if(i){let r=parseInt(i,10);if(!isNaN(r))return r}return n==="full"?this.activeFullSyncPlaceId:this.getDefaultRuntimePlaceId()}async handleSyncStatus(e,n){try{let i=u=>({state:"idle",instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,syncRoot:u,activeClientId:null,reverseSyncAvailable:!1,modifiedFileCount:0,autoApplyDeletes:!1,reverseDetectorActive:!1,reverseDetectorMode:ut,fileWatcherActive:!1}),r=this.resolveQueryPlaceId(e);if(r==null){let u=i(this.config.getSyncRoot());n.status(200).json(u);return}let a=this.places.get(r);if(!a){let u=i(this.config.getPlaceRoot(r));n.status(200).json(u);return}let o=a.fileWatcher?.getPendingCount()??0,s=a.fileWatcher?.isActivelyScanning()??!1,c=a.fileWatcher!==null;this.touchRuntimePlace(r);let l={state:a.state,instanceCount:a.instanceCount,scriptCount:a.scriptCount,lastFullSync:a.lastFullSync,lastIncrementalSync:a.lastIncrementalSync,syncRoot:this.config.getPlaceRoot(r),activeClientId:a.activeClientId,reverseSyncAvailable:o>0,modifiedFileCount:o,applyModes:a.applyModes,autoApplyDeletes:a.autoApplyDeletes,directions:a.directions,reverseDetectorActive:s,reverseDetectorMode:ut,fileWatcherActive:c,forwardOnlyClasses:[...cl]};n.status(200).json(l)}catch(i){this.sendError(n,i,"handleSyncStatus")}}async handleSyncStop(e,n){try{let i=e.body,r=i.placeId??this.getDefaultRuntimePlaceId(),a=lf(i);if(y.info("handleSyncStop requested",{placeId:r,clientId:i.clientId??null,identityScope:a,reason:i.reason??"requested"}),r==null){n.status(200).json({status:"idle",state:"idle",placeId:null,message:"No active sync place"});return}let o=this.places.get(r);if(!o){y.info("handleSyncStop no place context",{placeId:r,clientId:i.clientId??null}),n.status(200).json({status:"idle",state:"idle",placeId:r,message:`No sync context for place ${r}`});return}let s=!!(i.clientId&&o.activeClientId&&i.clientId!==o.activeClientId),c=o.activeFullSyncSessionId!==null||o.state==="syncing"||o.state==="initializing",l=!!(a&&o.activeSyncIdentityScope&&a===o.activeSyncIdentityScope);if(s&&c&&!l){y.warn("handleSyncStop rejected due to active client mismatch",{placeId:r,requestedClientId:i.clientId,activeClientId:o.activeClientId,requestedIdentityScope:a,activeIdentityScope:o.activeSyncIdentityScope,state:o.state,activeFullSyncSessionId:o.activeFullSyncSessionId}),n.status(409).json({error:"Conflict",message:`This sync session belongs to client ${o.activeClientId}`});return}s&&l&&y.info("handleSyncStop accepted stale client cleanup by identity scope",{placeId:r,requestedClientId:i.clientId,activeClientId:o.activeClientId,identityScope:a,state:o.state});let u=o.activeFullSyncSessionId,d=o.state,p=o.fileWatcher!==null;if(u&&(this.initHandler.clearPreserveLocalFiles(u),this.initHandler.clearPendingServiceTrees(u)),o.fileWatcher&&(y.info("handleSyncStop suspending reverse detector",{placeId:r,state:o.state,activeClientId:o.activeClientId,mode:ut}),o.fileWatcher.beginFullSyncReplacement()),o.incompleteSyncTimer&&(clearTimeout(o.incompleteSyncTimer),o.incompleteSyncTimer=null),u){let f=this.config.getPlaceRoot(r),m=TE.join(f,`explorer_tmp_${u}`);await Pl.rm(m,{recursive:!0,force:!0}).catch(()=>{})}o.tmpWriter&&(o.tmpWriter.stopChangeLogFlusher(),o.tmpWriter=null),o.tmpIndex=null,o.collisionDirMap=null,o.activeSyncIdentityScope=null,o.syncInitRequestsInFlight=0,o.activeFullSyncSessionId=null,o.syncProgress=null,o.state="idle",o.activeClientId=null,o.instanceCount=0,o.scriptCount=0,o.forwardRestoreQueue=[],this.activeFullSyncPlaceId===r&&(this.activeFullSyncPlaceId=null),this.clearRuntimePlaceIfMatch(r),y.info("handleSyncStop responding idle",{placeId:r,previousState:d,activeFullSyncSessionId:u,hadWatcher:p}),y.info("Sync stopped",{placeId:r,reason:i.reason??"requested"}),n.status(200).json({status:"stopped",state:"idle",placeId:r})}catch(i){this.sendError(n,i,"handleSyncStop")}}async initialize(){try{await this.config.loadFromMeta(),await this.initHandler.cleanupStaleTempDirs(),y.info("SyncController initialized")}catch(e){y.error("SyncController initialization failed",e instanceof Error?e:new Error(String(e)))}}async shutdown(){try{y.info("SyncController shutdown: clearing place contexts",{placeCount:this.places.size}),this.places.clear(),y.info("SyncController shut down")}catch(e){y.error("SyncController shutdown error",e instanceof Error?e:new Error(String(e)))}}async atomicWriteFile(e,n){let i=e+".tmp."+Bfe().slice(0,8);try{await Pl.writeFile(i,n,"utf-8"),await Pl.rename(i,e)}catch(r){throw await Pl.unlink(i).catch(()=>{}),r}}async handlePreCheck(e,n){try{await this.apiHandler.handlePreCheck(e,n)}catch(i){this.sendError(n,i,"handlePreCheck")}}async handleSyncDirections(e,n){try{await this.apiHandler.handleSyncDirections(e,n)}catch(i){this.sendError(n,i,"handleSyncDirections")}}async handleForwardRestoreList(e,n){try{await this.apiHandler.handleForwardRestoreList(e,n)}catch(i){this.sendError(n,i,"handleForwardRestoreList")}}async handleReversePending(e,n){try{await this.reverseHandler.handleReversePending(e,n)}catch(i){this.sendError(n,i,"handleReversePending")}}async handleReverseSyncChanges(e,n){try{await this.reverseHandler.handleReverseSyncChanges(e,n)}catch(i){this.sendError(n,i,"handleReverseSyncChanges")}}async handleReverseSyncResult(e,n){try{await this.reverseHandler.handleReverseSyncResult(e,n)}catch(i){this.sendError(n,i,"handleReverseSyncResult")}}async handleResolveConflict(e,n){try{await this.reverseHandler.handleResolveConflict(e,n)}catch(i){this.sendError(n,i,"handleResolveConflict")}}async handleReverseRescan(e,n){try{await this.reverseHandler.handleReverseRescan(e,n)}catch(i){this.sendError(n,i,"handleReverseRescan")}}async handleSyncHistory(e,n){try{await this.apiHandler.handleSyncHistory(e,n)}catch(i){this.sendError(n,i,"handleSyncHistory")}}async startFileWatcherForPlace(e){if(e.state!=="syncing"){y.debug("Skipping reverse detector start - place not syncing",{placeId:e.placeId,state:e.state});return}if(e.fileWatcher){if(e.fileWatcher.isActivelyScanning()){y.info("startFileWatcherForPlace: reusing active reverse detector",{placeId:e.placeId,mode:ut});return}y.info("startFileWatcherForPlace: resuming paused reverse detector",{placeId:e.placeId,mode:ut}),e.fileWatcher.endFullSyncReplacement();return}let n=this.createReverseChangeDetector(e);this.configureReverseChangeDetector(e,n),e.fileWatcher=n,n.start().then(()=>{e.fileWatcher===n&&y.info("Reverse detector started for reverse sync",{placeId:e.placeId,mode:ut})}).catch(i=>{y.warn("Failed to start reverse detector",{placeId:e.placeId,mode:ut,error:i instanceof Error?i.message:String(i)}),e.fileWatcher===n&&(e.fileWatcher=null)})}createReverseChangeDetector(e){return this.reverseDetectorFactory({explorerRoot:TE.join(this.config.getPlaceRoot(e.placeId),"explorer"),syncIndex:e.index,placeId:e.placeId})}configureReverseChangeDetector(e,n){e.writer.setOnWriteCallback(i=>{n.suppressPath(i)}),n.setDirectionChecker(i=>{let r=I6(i);return e.directions[r]}),n.setOnForwardViolation(i=>{e.forwardRestoreQueue.includes(i)||(e.forwardRestoreQueue.push(i),y.info("Forward violation queued for restore",{placeId:e.placeId,relativePath:i,queueSize:e.forwardRestoreQueue.length}))})}getStatusSummary(){return this.apiHandler.getStatusSummary()}getDirectionForCategory(e){return this.apiHandler.getDirectionForCategory(e)}getStatusDirect(e){return this.apiHandler.getStatusDirect(e)}async getHistoryDirect(e,n){return this.apiHandler.getHistoryDirect(e,n)}getDirectionsDirect(e){return this.apiHandler.getDirectionsDirect(e)}getProgressDirect(e){return this.apiHandler.getProgressDirect(e)}async readSyncedFile(e,n){return this.apiHandler.readSyncedFile(e,n)}async writeSyncedFile(e,n,i){await this.apiHandler.writeSyncedFile(e,n,i)}async executeViaDisk(e,n){return this.apiHandler.executeViaDisk(e,n)}sendError(e,n,i){let r=n instanceof Error?n.message:String(n);if(r.includes("Path traversal detected")){e.status(403).json({error:"Forbidden",message:r});return}let a=n.code;if(a==="ENOSPC"||a==="EPERM"||a==="EACCES"){y.warn(`SyncController.${i} disk error`,{code:a,message:r}),e.status(500).json({error:"Disk error",message:r,code:a,operation:i});return}y.error(`SyncController.${i} failed`,n instanceof Error?n:new Error(r)),e.status(500).json({error:"Internal error",message:`${i}: ${r}`})}};import{randomUUID as Vfe}from"crypto";function Y8(t,e){let n=Vfe(),i=n.replace(/-/g,"").substring(0,8).toUpperCase(),r=`${i.substring(0,4)}-${i.substring(4,8)}`;return{config:t,app:e,instanceId:n,sessionId:r,startTime:Date.now(),baseUrl:`http://${t.httpHost}:${t.httpPort}`,commandQueue:new Map,pendingCommands:new Map,globalPendingCommands:[],totalCommandsProcessed:0,pluginClients:new Map,pluginCommandSessionsByClientId:new Map,pluginCommandClientIdsByProcessToken:new Map,mcpInstances:new Map,cachedSelectionMap:new Map,studioRoutingMode:"recentPriority",pinnedTargetClientId:null,isClientMode:!1,clientModeHealthTimer:null,clientModeConsecutiveHealthFailures:0,clientModeUpstreamReachable:!0,clientModeUpstreamContextCaptureEnabled:!0,clientModeLastHealthSuccessAt:null,clientModeLastHealthFailureAt:null,clientModeLastHealthError:null,shuttingDown:!1,onUpstreamPermanentlyDown:null,clientModeIdleTimeoutMs:t.clientModeIdleTimeoutMs??36e5,clientModeIdleWatchdogTimer:null,shutdownFn:null,historyManager:null,analyticsManager:null,executionContextManager:null,licenseState:null,syncController:null,internalCommandExecutor:null,dashboardFolderPicker:null,assetLibraryOpenCloudServiceFactory:null,activeSyncOwnerInstanceId:null,activeProjectRoot:null,pendingDashboardSyncRootPin:null,playtestControlCommand:null,dashboardSyncRootSwitchInFlight:!1,uiStudioRecorders:new Map,aiClientName:"",pluginVersion:"",syncedSessionToken:null,serverLastCommandAt:null}}var X8=Pt(Ta(),1);ce();function Q8(t){let e=X8.default.json({limit:"5mb"});t.app.use((n,i,r)=>{if(n.path.startsWith("/sync/")){r();return}e(n,i,r)}),t.app.use((n,i,r)=>{i.setHeader("Access-Control-Allow-Origin","http://localhost:3002"),i.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),i.setHeader("Access-Control-Allow-Headers","Content-Type"),r()}),t.app.use((n,i,r)=>{y.debug(`${n.method} ${n.path}`,{ip:n.ip}),r()})}xa();import{randomUUID as Yx}from"crypto";xa();ce();function Wfe(){let t=process.env.WEPPY_ROBLOX_MCP_VERSION?.trim();return t||null}var Xe=Wfe()??"2.10.1";wi();tr();ff();Da();fl();xa();Da();var aq="studio-",Kfe=/^studio-[1-9]\d*$/;function Ix(t){return Kfe.test(t)}function oq(t,e){let n=new Set;for(let i of t)e!==void 0&&i.clientId===e||i.targetAlias&&Ix(i.targetAlias)&&n.add(i.targetAlias);return n}function Jfe(t,e){let n=oq(t,e),i=1;for(;n.has(`${aq}${i}`);)i+=1;return`${aq}${i}`}function kx(t,e){let n=oq(t,e.clientId);return e.targetAlias&&Ix(e.targetAlias)&&!n.has(e.targetAlias)||(e.targetAlias=Jfe(t,e.clientId)),e.targetAlias}fl();function Px(t){for(let e of t)kx(t,e)}function Rx(t){let e={clientId:t.clientId,targetAlias:t.targetAlias??t.clientId.slice(0,8),lastSeen:t.lastSeen,connectedAt:t.connectedAt,transport:"websocket",connectionState:t.commandSessionState??Ze.CONNECTED};return t.placeId!==void 0&&(e.placeId=t.placeId),t.placeName!==void 0&&(e.placeName=t.placeName),t.pluginVersion!==void 0&&(e.pluginVersion=t.pluginVersion),t.studioVersion!==void 0&&(e.studioVersion=t.studioVersion),t.lastRoutedAt!==void 0&&(e.lastRoutedAt=t.lastRoutedAt),t.processToken!==void 0&&(e.processToken=t.processToken),t.inFlightRequestId!==void 0&&(e.inFlightRequestId=t.inFlightRequestId),t.studioState!==void 0&&(e.studioState=t.studioState),t.studioStateSource!==void 0&&(e.studioStateSource=t.studioStateSource),t.studioStateUpdatedAt!==void 0&&(e.studioStateUpdatedAt=t.studioStateUpdatedAt),t.playtestMode!==void 0&&(e.playtestMode=t.playtestMode),e}function ME(t){let e=Cn(t);return Px(e),ef(e.map(Rx),null)}function Ex(t){let e=new Set;t.aiClientName&&e.add(t.aiClientName);for(let n of t.mcpInstances.values())n.aiClientName&&e.add(n.aiClientName);return Array.from(e)}function sq(t){let n=Date.now();for(let[i,r]of t.mcpInstances)r.lastSeen&&n-r.lastSeen>15e3&&(t.mcpInstances.delete(i),r.sessionId&&t.executionContextManager?.endSession(r.sessionId),y.debug("Removed stale MCP instance",{instanceId:i,lastSeen:r.lastSeen}))}function cq(t,e,n){let i=e.query.clientId;if(i&&t.pluginClients.has(i)){let r=t.pluginClients.get(i);r.lastSeen=Date.now()}try{let r=e.body;if(!r||!Array.isArray(r.selection)||typeof r.count!="number"){y.warn("Invalid selection update request",{body:r}),n.status(400).json({error:"Invalid request body"});return}let a=i||"unknown",o=Date.now();t.cachedSelectionMap.set(a,{selection:r.selection,count:r.count,timestamp:o,clientId:a}),y.debug("Selection cache updated",{count:r.count,clientId:a,timestamp:o}),n.json({status:"ok",timestamp:o})}catch(r){y.error("Error handling selection update",r),n.status(500).json({error:"Internal server error"})}}function lq(t,e,n){let i=parseInt(e.query.maxAge)||3e4,r=mf(t,i);r?n.json({cached:!0,...r}):n.json({cached:!1,message:"No cached selection available"})}function mf(t,e=3e4,n){if(t.cachedSelectionMap.size===0)return null;let i;if(n)i=t.cachedSelectionMap.get(n);else for(let a of t.cachedSelectionMap.values())(!i||a.timestamp>i.timestamp)&&(i=a);if(!i)return null;let r=Date.now()-i.timestamp;return e===0||r<=e?i:null}function zE(t,e){let n=t.pluginClients.get(e.clientId),i=Date.now(),r=[...t.pluginClients.values()].filter(c=>c.clientId===e.clientId||c.commandSessionState!==Ze.DISCONNECTED),a=n??{clientId:e.clientId,connectedAt:i,lastSeen:i,commandsProcessed:0,connectionType:"polling"},o=kx(r,a),s={clientId:e.clientId,targetAlias:o,projectName:e.projectName??n?.projectName,placeName:e.placeName??n?.placeName,placeId:e.placeId??n?.placeId,pluginVersion:e.pluginVersion??n?.pluginVersion,studioVersion:e.studioVersion??n?.studioVersion,connectedAt:n?.connectedAt||i,lastSeen:i,commandsProcessed:n?.commandsProcessed||0,connectionType:n?.connectionType||"polling",inFlightRequestId:n?.inFlightRequestId,studioState:n?.studioState,studioStateSource:n?.studioStateSource,studioStateUpdatedAt:n?.studioStateUpdatedAt,playtestMode:n?.playtestMode,...n?.commandSessionState?{commandSessionState:n.commandSessionState}:{},...n?.processToken?{processToken:n.processToken}:{}};return t.pluginClients.set(e.clientId,s),t.syncController&&typeof t.syncController.setCurrentConnectedPlace=="function"&&typeof e.placeId=="number"&&Number.isFinite(e.placeId)&&t.syncController.setCurrentConnectedPlace(e.placeId,e.placeName??null),t.pendingCommands.has(e.clientId)||t.pendingCommands.set(e.clientId,[]),e.pluginVersion&&(t.pluginVersion=e.pluginVersion),typeof s.placeId=="number"&&Number.isFinite(s.placeId)&&ex(t,s.placeId,s.placeName??null),t.analyticsManager&&(e.pluginVersion&&t.analyticsManager.setPluginVersion(e.pluginVersion),t.analyticsManager.trackPluginConnected()),y.info("Plugin client registered",{clientId:e.clientId,targetAlias:o,projectName:e.projectName,placeName:e.placeName,isReconnect:!!n}),{clientInfo:s,sessionId:t.sessionId,mcpVersion:Xe,mcpInstanceCount:t.mcpInstances.size+1,aiClientNames:Ex(t)}}function LE(t,e){let n=t.pluginClients.get(e),i=t.pluginClients.has(e),r=n?.commandSessionState===Ze.CONNECTED;if(t.pluginClients.delete(e),t.pendingCommands.delete(e),i&&pl(t,e),i&&t.syncController&&typeof t.syncController.clearCurrentConnectedPlaceIfMatch=="function"&&typeof n?.placeId=="number"&&Number.isFinite(n.placeId)){let a=[...t.pluginClients.values()].filter(o=>typeof o.placeId=="number"&&Number.isFinite(o.placeId)).sort((o,s)=>s.lastSeen-o.lastSeen)[0];a?t.syncController.setCurrentConnectedPlace?.(a.placeId??null,a.placeName??null):t.syncController.clearCurrentConnectedPlaceIfMatch(n.placeId)}return r&&tf(t,e,"disconnected",n),y.info("Plugin client unregistered",{clientId:e,existed:i}),i}function Tx(t,e,n){try{let i=e.body;if(!i.clientId){n.status(400).json({error:"Missing clientId"});return}let r=zE(t,{clientId:i.clientId,projectName:i.projectName,placeName:i.placeName,placeId:i.placeId,pluginVersion:i.pluginVersion,studioVersion:i.studioVersion});n.json({status:"ok",clientId:i.clientId,targetAlias:r.clientInfo.targetAlias,serverInstanceId:t.instanceId,sessionId:r.sessionId,mcpVersion:r.mcpVersion,connectedAt:r.clientInfo.connectedAt,aiClientNames:r.aiClientNames,serverStartTime:t.startTime,mcpInstanceCount:r.mcpInstanceCount})}catch(i){y.error("Error registering plugin client",i),n.status(500).json({error:"Internal server error"})}}function Ax(t,e,n){let i=e.body?.clientId;if(!i){n.status(400).json({error:"Missing clientId"});return}let r=LE(t,i);n.json({status:"ok",existed:r})}function uq(t,e,n){try{let i=e.body;if(!i.instanceId){n.status(400).json({error:"Missing instanceId"});return}let r=Date.now(),a={instanceId:i.instanceId,...typeof i.sessionId=="string"?{sessionId:i.sessionId}:{},pid:i.pid,connectedAt:r,isServer:!1,lastSeen:r};i.aiClientName&&(a.aiClientName=i.aiClientName),i.cwd&&(a.cwd=i.cwd),"projectRoot"in i&&(a.projectRoot=i.projectRoot),t.mcpInstances.set(i.instanceId,a),rt(t,"mcp_status",{aiClientName:a.aiClientName??"Unknown",instanceId:i.instanceId,status:"registered"}),yl(t,{timestamp:new Date().toISOString(),type:"mcp",status:"registered",instanceId:i.instanceId,message:`MCP registered \u2014 ${a.aiClientName??i.instanceId}`,...a.aiClientName?{aiClientName:a.aiClientName}:{}}),y.info("MCP instance registered (client mode)",{instanceId:i.instanceId,pid:i.pid,cwd:i.cwd}),n.json({status:"ok",instanceId:i.instanceId,serverInstanceId:t.instanceId,sessionId:t.sessionId,mcpVersion:Xe,mcpInstanceCount:t.mcpInstances.size+1})}catch(i){y.error("Error registering MCP instance",i),n.status(500).json({error:"Internal server error"})}}function dq(t,e,n){let i=e.body?.instanceId;if(!i){n.status(400).json({error:"Missing instanceId"});return}let r=t.mcpInstances.get(i),a=!!r;t.mcpInstances.delete(i),r?.sessionId&&t.executionContextManager?.endSession(r.sessionId),a&&(rt(t,"mcp_status",{aiClientName:r?.aiClientName??"Unknown",instanceId:i,status:"unregistered"}),yl(t,{timestamp:new Date().toISOString(),type:"mcp",status:"unregistered",instanceId:i,message:`MCP unregistered \u2014 ${r?.aiClientName??i}`,...r?.aiClientName?{aiClientName:r.aiClientName}:{}})),y.info("MCP instance unregistered",{instanceId:i,existed:a}),n.json({status:"ok",existed:a})}function pq(t,e,n){let{instanceId:i,aiClientName:r}=e.body;if(i&&r){let a=t.mcpInstances.get(i);a&&(a.aiClientName=r)}n.json({status:"ok"})}function fq(t){let e=3e4,n=Date.now(),i=_r({appDataDir:t.config.appDataDir});for(let[a,o]of t.pluginClients)n-o.lastSeen>e&&(t.pluginClients.delete(a),t.pendingCommands.delete(a),pl(t,a));sq(t);let r=Cn(t);return Px(r),{serverInstanceId:t.instanceId,sessionId:t.sessionId,mcpVersion:Xe,uptime:n-t.startTime,serverStartTime:t.startTime,serverExecutable:process.execPath,serverHost:t.config.httpHost,serverPort:t.config.httpPort,serverPid:process.pid,pluginClients:r.map(Rx),studioRoutingMode:t.studioRoutingMode,pinnedTargetClientId:t.pinnedTargetClientId,mcpInstances:[{instanceId:t.instanceId,pid:process.pid,connectedAt:t.startTime,isServer:!0,cwd:process.cwd(),projectRoot:i,lastSeen:n,...t.aiClientName?{aiClientName:t.aiClientName}:{}},...Array.from(t.mcpInstances.values())],mcpInstanceCount:t.mcpInstances.size+1}}function $x(t,e){e.json(fq(t))}function Ox(t,e,n){let i=e.query.instanceId;i&&t.mcpInstances.has(i)&&(t.mcpInstances.get(i).lastSeen=Date.now()),sq(t);let r=Cn(t);Px(r);let s={...{status:"online",connectedClients:r.length,queuedCommands:l8(t),uptime:Date.now()-t.startTime,version:Xe,enableContextCapture:t.executionContextManager?.isEnabled()??t.config.enableContextCapture??!0,isClientMode:t.isClientMode,shuttingDown:t.shuttingDown,pid:process.pid,sessionId:t.sessionId,nodeVersion:process.version,studioRoutingMode:t.studioRoutingMode,pinnedTargetClientId:t.pinnedTargetClientId},instanceId:t.instanceId,mcpInstanceCount:t.mcpInstances.size+1,aiClientNames:Ex(t),pluginVersion:t.pluginVersion||void 0,dashboardSseClients:t.dashboardSseClients?.size??0,websocketClients:r.length,pluginClients:r.map(Rx),...t.isClientMode?{upstream:{reachable:t.clientModeUpstreamReachable,consecutiveFailures:t.clientModeConsecutiveHealthFailures,lastSuccessAt:t.clientModeLastHealthSuccessAt,lastFailureAt:t.clientModeLastHealthFailureAt,lastError:t.clientModeLastHealthError,baseUrl:t.baseUrl}}:{}};n.json(s)}function mq(t,e,n,i){let r=e.ip||e.socket.remoteAddress||"";if(!(r==="127.0.0.1"||r==="::1"||r==="::ffff:127.0.0.1"||r==="localhost")){y.warn("Shutdown request rejected from non-localhost",{ip:r}),n.status(403).json({error:"Forbidden: localhost only"});return}y.info("Shutdown request received, initiating graceful shutdown",{requestedBy:r,uptime:Date.now()-t.startTime}),n.json({status:"shutting_down",message:"Server will shutdown gracefully",pid:process.pid}),setTimeout(async()=>{try{await i(),y.info("Graceful shutdown completed"),process.exit(0)}catch(o){y.error("Error during graceful shutdown",o),process.exit(1)}},100)}async function Dx(t){if(t.isClientMode)try{let e=await fetch(`${t.baseUrl}/connection-info`);if(e.ok)return await e.json()}catch(e){y.warn("Failed to fetch connection info from server",{error:e})}return fq(t)}Da();var dt={bridgeRunTest:"manage_studio_run_test_bridge",placeInfo:"system_info_place_info",clearLogs:"manage_logs_clear",createScript:"manage_scripts_create",getLogs:"manage_logs_get",deleteScript:"manage_scripts_delete",canonical:{playStart:"manage_studio_play_start",playStop:"manage_studio_play_stop",playPause:"manage_studio_play_pause",playResume:"manage_studio_play_resume",playStatus:"manage_studio_play_status",runTest:"manage_studio_run_test"}},Xfe=new Set([dt.canonical.runTest]),Qfe=new Set([dt.canonical.playStop]),q4e=new Set([dt.canonical.playStart,dt.canonical.playStop,dt.canonical.playPause,dt.canonical.playResume,dt.canonical.playStatus]);function Jr(t){return Xfe.has(t)}function gf(t){return Qfe.has(t)}var V4e=dt.canonical.playStop,gq=[5e3,15e3];fl();var eme=new Set(["manage_assets_export_selection_rbxm","manage_assets_export_path_rbxm","manage_assets_review_model","manage_assets_generate_model","manage_assets_import_rbxm","manage_assets_generate_thumbnail"]),on=class t extends Error{code;routing;constructor(e,n,i){super(n),this.name="CommandTargetSelectionError",this.code=e,this.routing=i,Object.setPrototypeOf(this,t.prototype)}};function tme(t={},e){let n={},i=t.clientId,r=t.targetAlias,a=t.placeId;if(i!==void 0){if(typeof i!="string"||i.trim().length===0)throw new on("invalid_target_selector","clientId target selector must be a non-empty string",{selectionMode:"clientId",...typeof i=="string"?{requestedClientId:i.trim()}:{}});n.requestedClientId=i.trim()}if(r!==void 0){if(typeof r!="string"||r.trim().length===0)throw new on("invalid_target_selector","targetAlias target selector must be a non-empty string",{selectionMode:"targetAlias",...typeof r=="string"?{requestedTargetAlias:r.trim()}:{}});n.requestedTargetAlias=r.trim()}if(a!==void 0&&nme(e,t)){if(typeof a!="number"||!Number.isFinite(a))throw new on("invalid_target_selector","placeId target selector must be a finite number",{selectionMode:"placeId"});n.requestedPlaceId=a}return n}function Nx(t,e,n={},i){let r=tme(n,i),a=z6(e,t.studioRoutingMode==="pinned"?t.pinnedTargetClientId:null);if(r.requestedClientId!==void 0)return rme(a,r);if(r.requestedTargetAlias!==void 0)return ime(a,r);if(r.requestedPlaceId!==void 0)return ame(a,r);if(t.studioRoutingMode==="pinned"&&t.pinnedTargetClientId!==null){let s=a.find(c=>c.clientId===t.pinnedTargetClientId);if(s)return{targetClientId:s.clientId,routing:Pr("pinnedTarget",r,s)}}let o=a[0];return o?{targetClientId:o.clientId,routing:Pr("recentPriority",r,o)}:{routing:{selectionMode:"globalQueue"}}}function nme(t,e){return!t||!eme.has(t)?!0:e.scope==="shared"}function rme(t,e){let n=t.find(i=>i.clientId===e.requestedClientId);if(!n)throw new on("target_client_not_found",`Target client not found: ${e.requestedClientId}`,Pr("clientId",e));if(e.requestedTargetAlias!==void 0&&n.targetAlias!==e.requestedTargetAlias)throw new on("target_selector_mismatch",`Target client ${n.clientId} does not match targetAlias ${e.requestedTargetAlias}`,Pr("clientId",e,n));return hq("clientId",e,n),{targetClientId:n.clientId,routing:Pr("clientId",e,n)}}function ime(t,e){let n=t.find(i=>i.targetAlias!==void 0&&Ix(i.targetAlias)&&i.targetAlias===e.requestedTargetAlias);if(!n)throw new on("target_alias_not_found",`Target alias not found: ${e.requestedTargetAlias}`,Pr("targetAlias",e));return hq("targetAlias",e,n),{targetClientId:n.clientId,routing:Pr("targetAlias",e,n)}}function ame(t,e){let n=t.filter(r=>r.placeId===e.requestedPlaceId);if(n.length===0)throw new on("target_place_not_found",`Target place not found: ${e.requestedPlaceId}`,Pr("placeId",e));if(n.length>1)throw new on("target_place_ambiguous",`Target place is ambiguous: ${e.requestedPlaceId}`,Pr("placeId",e));let i=n[0];return{targetClientId:i.clientId,routing:Pr("placeId",e,i)}}function hq(t,e,n){if(e.requestedPlaceId!==void 0&&n.placeId!==e.requestedPlaceId)throw new on("target_selector_mismatch",`Target client ${n.clientId} is not connected to placeId ${e.requestedPlaceId}`,Pr(t,e,n))}function Pr(t,e,n){let i={selectionMode:t};return e.requestedClientId!==void 0&&(i.requestedClientId=e.requestedClientId),e.requestedTargetAlias!==void 0&&(i.requestedTargetAlias=e.requestedTargetAlias),e.requestedPlaceId!==void 0&&(i.requestedPlaceId=e.requestedPlaceId),n!==void 0&&(i.actualClientId=n.clientId,n.targetAlias!==void 0&&(i.actualTargetAlias=n.targetAlias),n.placeId!==void 0&&(i.actualPlaceId=n.placeId),n.placeName!==void 0&&(i.actualPlaceName=n.placeName)),i}eE();ce();uf();var Tl={query_instances:{discriminator:"action",validActions:new Set(["get","children","find_child","find_descendant","wait_for_child","class_info","search_name","search_class","search_property","search_tag","file_tree","project_structure","descendants","ancestors"]),paramAliases:{query_instances_search_name:{query:"pattern"},query_instances_search_property:{root:"rootPath"},query_instances_search_tag:{root:"rootPath"},query_instances_project_structure:{root:"rootPath"}}},mutate_instances:{discriminator:"action",validActions:new Set(["create","create_with_props","delete","clone","move","rename","pivot","create_tree","mass_create","mass_delete","mass_duplicate","smart_duplicate"]),paramAliases:{mutate_instances_clone:{path:"sourcePath"},mutate_instances_smart_duplicate:{spacing:"offset"}}},manage_properties:{discriminator:"action",validActions:new Set(["get","set","get_all","set_multiple","get_attr","set_attr","get_all_attrs","delete_attr","add_tag","remove_tag","check_tag","get_tags","get_tagged","set_calculated","set_relative","mass_set","mass_get","modify_children"]),paramAliases:{manage_properties_get_tagged:{tagName:"tag",root:"rootPath"},manage_properties_set_relative:{amount:"value"}}},manage_scripts:{discriminator:"action",validActions:new Set(["get_source","set_source","create","delete","edit_replace","edit_insert","edit_delete","search","replace","get_dependencies"]),paramAliases:{manage_scripts_edit_replace:{newLines:"newContent"},manage_scripts_edit_insert:{lines:"content"},manage_scripts_replace:{pattern:"searchPattern"}}},manage_ui:{discriminator:"action",validActions:new Set(["design_brief","create_tree","update","delete","preview","check"])},manage_lighting:{discriminator:"action",validActions:new Set(["lighting","atmosphere","sky","terrain_props","time"])},manage_selection:{discriminator:"action",validActions:new Set(["get","set","clear","cached","context","details","add","remove","watch"])},manage_camera:{discriminator:"action",validActions:new Set(["info","focus_path","focus_position","suggest","screenshot"]),paramAliases:{manage_camera_suggest:{path:"targetPath"}}},manage_tween:{discriminator:"action",validActions:new Set(["create","play","pause","cancel"])},manage_audio:{discriminator:"action",validActions:new Set(["play","stop","pause","resume","set_listener"])},manage_animation:{discriminator:"action",validActions:new Set(["load","play","stop","get_tracks"])},manage_physics:{discriminator:"action",validActions:new Set(["register_group","set_collidable","get_groups"])},manage_effects:{discriminator:"action",validActions:new Set(["emit","clear","toggle"])},manage_terrain:{discriminator:"action",validActions:new Set(["fill_block","fill_ball","fill_cylinder","fill_wedge","clear_region","clear_bounds","replace_material","colors_get","colors_set","read_voxel","read_voxels","write_voxels","generate","smooth"])},spatial_query:{discriminator:"action",validActions:new Set(["raycast","find_ground","check_placement","multi_raycast","scan_area","find_flat","find_spawn","analyze_walkable","spatial_map","find_space","bounds","snap_grid","collision"]),paramAliases:{spatial_query_spatial_map:{path:"rootPath"}}},manage_assets:{discriminator:"action",validActions:new Set(["insert","info","search","search_insert","insert_free","insert_package","export_selection_json","export_selection_rbxm","export_path_rbxm","review_model","generate_model","upload_asset","import_rbxm","generate_thumbnail"]),paramAliases:{manage_assets_search:{maxResults:"limit"}}},manage_open_cloud_assets:{discriminator:"action",validActions:new Set(["credential_status","capabilities","upload","update","info","operation_status"])},manage_sync:{discriminator:"action",validActions:new Set(["status_current_place","history","directions","read_file","write_file","progress"])},workspace_state:{discriminator:"action",validActions:new Set(["sync","snapshot","changes","viewport","clear_history","metadata","scripts","selection_info","clear_cache"])},manage_logs:{discriminator:"action",validActions:new Set(["get","clear","errors"]),paramAliases:{manage_logs_get:{level:"type"}}},system_info:{discriminator:"action",validActions:new Set(["ping","connection","usage","place_info","services","studio_settings"])},manage_studio:{discriminator:"action",validActions:new Set(["toggle_ui_preview","play_start","play_stop","play_pause","play_resume","play_status","run_test"])}};var ome={manage_selection_cached:"internal",manage_open_cloud_assets_credential_status:"internal",manage_open_cloud_assets_capabilities:"internal",manage_open_cloud_assets_upload:"internal",manage_open_cloud_assets_update:"internal",manage_open_cloud_assets_info:"internal",manage_open_cloud_assets_operation_status:"internal",manage_sync_status_current_place:"internal",manage_sync_history:"internal",manage_sync_directions:"internal",manage_sync_read_file:"internal",manage_sync_write_file:"internal",manage_sync_progress:"internal",system_info_connection:"internal",manage_studio_run_test:"internal"};function jx(t){return ome[t]||"plugin"}var yq=new Set(["batch_execute","execute_luau","extended_call_method","extended_call_methods","extended_get_properties","extended_get_property","extended_set_properties","extended_set_property","manage_animation_get_tracks","manage_animation_load","manage_animation_play","manage_animation_stop","manage_assets_export_path_rbxm","manage_assets_export_selection_json","manage_assets_export_selection_rbxm","manage_assets_generate_model","manage_assets_generate_thumbnail","manage_assets_import_rbxm","manage_assets_info","manage_assets_insert","manage_assets_insert_free","manage_assets_insert_package","manage_assets_review_model","manage_assets_search","manage_assets_search_insert","manage_assets_upload_asset","manage_audio_pause","manage_audio_play","manage_audio_resume","manage_audio_set_listener","manage_audio_stop","manage_camera_screenshot","manage_effects_clear","manage_effects_emit","manage_effects_toggle","manage_lighting_atmosphere","manage_lighting_lighting","manage_lighting_sky","manage_lighting_terrain_props","manage_lighting_time","manage_open_cloud_assets_capabilities","manage_open_cloud_assets_credential_status","manage_open_cloud_assets_info","manage_open_cloud_assets_operation_status","manage_open_cloud_assets_update","manage_open_cloud_assets_upload","manage_physics_get_groups","manage_physics_register_group","manage_physics_set_collidable","manage_properties_mass_get","manage_properties_mass_set","manage_properties_modify_children","manage_properties_set_calculated","manage_properties_set_relative","manage_scripts_replace","manage_selection_add","manage_selection_context","manage_selection_details","manage_selection_remove","manage_selection_watch","manage_studio_play_pause","manage_studio_play_resume","manage_studio_play_start","manage_studio_play_status","manage_studio_play_stop","manage_studio_run_test","manage_studio_toggle_ui_preview","manage_sync_directions","manage_sync_history","manage_sync_progress","manage_sync_read_file","manage_sync_status_current_place","manage_sync_write_file","manage_terrain_clear_bounds","manage_terrain_clear_region","manage_terrain_colors_get","manage_terrain_colors_set","manage_terrain_fill_ball","manage_terrain_fill_block","manage_terrain_fill_cylinder","manage_terrain_fill_wedge","manage_terrain_generate","manage_terrain_read_voxel","manage_terrain_read_voxels","manage_terrain_replace_material","manage_terrain_smooth","manage_terrain_write_voxels","manage_tween_cancel","manage_tween_create","manage_tween_pause","manage_tween_play","manage_ui_check","manage_ui_create_tree","manage_ui_delete","manage_ui_design_brief","manage_ui_preview","manage_ui_update","mutate_instances_create_tree","mutate_instances_mass_create","mutate_instances_mass_delete","mutate_instances_mass_duplicate","mutate_instances_smart_duplicate","query_instances_ancestors","query_instances_descendants","query_instances_file_tree","query_instances_project_structure","query_instances_search_property","query_instances_search_tag","spatial_query_analyze_walkable","spatial_query_bounds","spatial_query_check_placement","spatial_query_collision","spatial_query_find_flat","spatial_query_find_ground","spatial_query_find_space","spatial_query_find_spawn","spatial_query_multi_raycast","spatial_query_raycast","spatial_query_scan_area","spatial_query_snap_grid","spatial_query_spatial_map","system_info_place_info","system_info_services","system_info_studio_settings","workspace_state_changes","workspace_state_clear_cache","workspace_state_clear_history","workspace_state_metadata","workspace_state_scripts","workspace_state_selection_info","workspace_state_snapshot","workspace_state_sync","workspace_state_viewport"]),UE=new Set(["system_info_connection","system_info_ping","system_info_usage"]);function zn(t){return yq.has(t)?"pro":"basic"}ki();Mx();import{readFile as Ime}from"node:fs/promises";import kme from"node:path";import{createHash as xme,randomUUID as HE}from"node:crypto";import{mkdir as xf,readFile as Pq,readdir as Rq,rename as Eq,rm as _me,stat as Sme,writeFile as qx}from"node:fs/promises";import zt from"node:path";import{extname as ume}from"node:path";import{stat as dme}from"node:fs/promises";var pme=20*1024*1024,Iq=[{category:"image",assetType:"Image",folder:"images",extensions:[".png",".jpeg",".jpg",".bmp",".tga"],supportsContentUpdate:!1,contentTypes:{".png":"image/png",".jpeg":"image/jpeg",".jpg":"image/jpeg",".bmp":"image/bmp",".tga":"image/tga"}},{category:"decal",assetType:"Decal",folder:"decals",extensions:[".png",".jpeg",".jpg",".bmp",".tga"],supportsContentUpdate:!1,contentTypes:{".png":"image/png",".jpeg":"image/jpeg",".jpg":"image/jpeg",".bmp":"image/bmp",".tga":"image/tga"}},{category:"audio",assetType:"Audio",folder:"audio",extensions:[".mp3",".ogg",".wav",".flac"],supportsContentUpdate:!1,contentTypes:{".mp3":"audio/mpeg",".ogg":"audio/ogg",".wav":"audio/wav",".flac":"audio/flac"}},{category:"mesh",assetType:"Mesh",folder:"meshes",extensions:[".mesh"],supportsContentUpdate:!1,contentTypes:{".mesh":"application/octet-stream"}},{category:"model",assetType:"Model",folder:"models",extensions:[".fbx",".gltf",".glb",".rbxm",".rbxmx"],supportsContentUpdate:!0,contentTypes:{".fbx":"model/fbx",".gltf":"model/gltf+json",".glb":"model/gltf-binary",".rbxm":"model/x-rbxm",".rbxmx":"model/x-rbxm"}},{category:"video",assetType:"Video",folder:"videos",extensions:[".mp4",".mov"],supportsContentUpdate:!1,contentTypes:{".mp4":"video/mp4",".mov":"video/quicktime"}},{category:"animation",assetType:"Animation",folder:"animations",extensions:[".rbxm",".rbxmx"],supportsContentUpdate:!0,contentTypes:{".rbxm":"model/x-rbxm",".rbxmx":"model/x-rbxm"}}],fme=new Map(Iq.map(t=>[t.category,t]));function xq(t){if(!t)throw new Error("Open Cloud asset upload is disabled in WEPPY Dashboard settings.")}function zx(t,e){return t.split(e.apiKey).join("[redacted]")}function qE(t){let e=fme.get(t);if(!e)throw new Error(`Unsupported asset category: ${t}`);return e}function Lx(t){return qE(t)}function _q(t,e){let n=t.creatorType??e.creatorType,i=t.creatorId??e.creatorId;if(!n||!i)throw new Error("creatorType and creatorId are required for Roblox Open Cloud asset upload/update.");return{...t,creatorType:n,creatorId:i}}async function Sq(t,e,n){let i=ume(e).toLowerCase(),r=t.contentTypes[i];if(!r)throw new Error(`Unsupported file extension ${i||"(none)"} for ${t.category}.`);if((await dme(e)).size>n)throw new Error(`Asset file is too large. Maximum size is ${n} bytes.`);return r}function wq(t){return typeof t.path=="string"&&t.path.startsWith("operations/")?t.path:null}function Cq(t,e,n,i){let r={apiKey:t.apiKey,operationId:e};return n!==void 0&&(r.intervalMs=n),i!==void 0&&(r.timeoutMs=i),r}var Al=class{client;credentialStore;isOpenCloudUploadEnabled;maxFileSizeBytes;constructor(e){this.client=e.client,this.credentialStore=e.credentialStore,this.isOpenCloudUploadEnabled=e.isOpenCloudUploadEnabled,this.maxFileSizeBytes=e.maxFileSizeBytes??pme}getCapabilities(){return Iq.map(({contentTypes:e,...n})=>n)}async uploadAsset(e){xq(this.isOpenCloudUploadEnabled());let n=await this.getRequiredCredential(),i=_q(e,n),r=qE(i.category),a=await Sq(r,i.filePath,this.maxFileSizeBytes);try{let o={apiKey:n.apiKey,assetType:r.assetType,displayName:i.displayName,description:i.description??"",creatorType:i.creatorType,creatorId:i.creatorId,filePath:i.filePath,contentType:a};i.expectedPrice!==void 0&&(o.expectedPrice=i.expectedPrice);let s=await this.client.createAsset(o);if(i.waitForOperation){let c=wq(s);return c?await this.client.pollOperation(Cq(n,c,i.operationPollIntervalMs,i.operationPollTimeoutMs)):s}return s}catch(o){throw new Error(zx(o instanceof Error?o.message:String(o),n))}}async updateAsset(e){xq(this.isOpenCloudUploadEnabled());let n=await this.getRequiredCredential(),i=_q(e,n),r=qE(i.category),a;if(i.filePath){if(!r.supportsContentUpdate)throw new Error(`${r.category} assets do not support content updates.`);a=await Sq(r,i.filePath,this.maxFileSizeBytes)}try{let o={apiKey:n.apiKey,assetId:i.assetId,assetType:r.assetType,creatorType:i.creatorType,creatorId:i.creatorId};i.filePath&&(o.filePath=i.filePath),a!==void 0&&(o.contentType=a),i.displayName!==void 0&&(o.displayName=i.displayName),i.description!==void 0&&(o.description=i.description),i.updateMask!==void 0&&(o.updateMask=i.updateMask),i.expectedPrice!==void 0&&(o.expectedPrice=i.expectedPrice);let s=await this.client.updateAsset(o);if(i.waitForOperation){let c=wq(s);return c?await this.client.pollOperation(Cq(n,c,i.operationPollIntervalMs,i.operationPollTimeoutMs)):s}return s}catch(o){throw new Error(zx(o instanceof Error?o.message:String(o),n))}}async getAsset(e){let n=await this.getRequiredCredential();try{let i={apiKey:n.apiKey,assetId:e.assetId};return e.readMask!==void 0&&(i.readMask=e.readMask),await this.client.getAsset(i)}catch(i){throw new Error(zx(i instanceof Error?i.message:String(i),n))}}async getOperation(e){let n=await this.getRequiredCredential();try{return await this.client.getOperation({apiKey:n.apiKey,operationId:e.operationId})}catch(i){throw new Error(zx(i instanceof Error?i.message:String(i),n))}}async getRequiredCredential(){let e=await this.credentialStore.getCredentialForUse();if(!e)throw new Error("Configure a Roblox Open Cloud API key in WEPPY Dashboard before using Open Cloud asset upload.");return e}};import kq from"node:fs";import Jt from"node:path";Ob();var mme=/^asset_(image|decal|audio|mesh|model|video|animation)_\d+_[a-z0-9]+$/;function gme(t){if(!Number.isInteger(t)||t<0)throw new Error(`Invalid place ID: ${t}`)}function hme(t,e){try{return kq.statSync(Jt.join(t,e,".sync-meta.json")).isFile()}catch{return!1}}function yme(t,e){gme(e.placeId);let n=`place_${e.placeId}`,i=e.placeName?ol(e.placeName):"",r=i?`${n}_${i}`:n,a=[];try{let o=new RegExp(`^place_${e.placeId}(?:_.*)?$`);a=kq.readdirSync(t,{withFileTypes:!0}).filter(s=>s.isDirectory()&&o.test(s.name)).map(s=>s.name).sort()}catch{return r}return i&&a.includes(r)?r:a.find(o=>hme(t,o))??(a.includes(r)?r:null)??a[0]??r}function BE(t){let e=Jt.resolve(t.projectSyncRoot),n=Lx(t.category).folder,i=t.scope.kind==="place"?Jt.join(e,yme(e,t.scope),"assets",n):Jt.join(e,"shared-assets",n);return{root:i,inbox:Jt.join(i,"inbox"),index:Jt.join(i,".asset-library-index.json")}}function vme(t){let e=mme.exec(t);return e?.[1]?e[1]:null}function yf(t,e){let n=vme(t);return n?e?n===e:!0:!1}function Ux(t,e){if(!yf(t,e))throw new Error(`Invalid asset ID: ${t}`)}function Yr(t,e){let n=Jt.relative(Jt.resolve(t),Jt.resolve(e));return n===""||!n.startsWith("..")&&!Jt.isAbsolute(n)}function bme(t){Ux(t.assetId,t.category);let e=BE(t),n=Jt.resolve(e.root,t.assetId);if(!Yr(e.root,n))throw new Error(`Invalid asset path for ${t.assetId}`);return n}function Fx(t){let e=bme(t),n=Jt.resolve(e,t.relativeFileName);if(!Yr(e,n))throw new Error(`Invalid asset file path for ${t.assetId}`);return n}function vf(t,e){return Jt.relative(Jt.resolve(t),Jt.resolve(e)).split(Jt.sep).join("/")}var Tq=20*1024*1024,wme=200;function Aq(t,e){return t.kind!==e.kind?!1:t.kind==="shared"&&e.kind==="shared"?!0:t.kind==="place"&&e.kind==="place"&&t.placeId===e.placeId}function $q(t,e){let n=zt.extname(t).toLowerCase(),i=Lx(e);if(!i.extensions.includes(n))return null;let r=i.contentTypes[n];return r?{canonicalExt:n,mimeType:r}:null}function ZE(t,e,n){if(e!=="image"&&e!=="decal")return!0;let i=zt.extname(t).toLowerCase();return i===".png"?n.length>=8&&n[0]===137&&n[1]===80&&n[2]===78&&n[3]===71&&n[4]===13&&n[5]===10&&n[6]===26&&n[7]===10:i===".jpg"||i===".jpeg"?n.length>=3&&n[0]===255&&n[1]===216&&n[2]===255:i===".bmp"?n.length>=2&&n[0]===66&&n[1]===77:i===".tga"?n.length>0:!1}function Oq(t){return xme("sha256").update(t).digest("hex")}function Bx(t){return t.now?.()??Date.now()}function Cme(t){return(t.randomId?.()??HE().replace(/-/g,"").slice(0,6)).toLowerCase().replace(/[^a-z0-9]/g,"").slice(0,12)||"asset"}function Dq(t,e){let n=Math.floor(Bx(t)/1e3);for(let i=0;i<20;i++){let r=Cme(t),a=i===0?`asset_${t.category}_${n}_${r}`:`asset_${t.category}_${n}_${r}${i}`;if(!e.has(a))return a}return`asset_${t.category}_${n}_${HE().replace(/-/g,"").slice(0,10)}`}function Nq(t){let e=zt.parse(t).name.trim();return e.length>0?e:t}function jq(t){if(t.mimeType!=="image/png")throw new Error("Asset Library preview must be an image/png thumbnail");if(zt.basename(t.fileName).toLowerCase()!=="thumbnail.png")throw new Error("Asset Library preview file must be thumbnail.png");if(!ZE("thumbnail.png","image",t.content))throw new Error("Asset Library preview is not a valid PNG file");return{fileName:"thumbnail.png",content:t.content}}async function VE(t,e){let n=`${t}.tmp.${HE().slice(0,8)}`;await qx(n,JSON.stringify(e,null,2),"utf8"),await Eq(n,t)}async function Mq(t,e){try{let n=await Pq(zt.join(e,"asset.json"),"utf8"),i=JSON.parse(n);return!yf(i.id,t.category)||i.category!==t.category||!Aq(i.scope,t.scope)?null:i}catch{return null}}async function bf(t,e){let n;try{n=await Rq(e.root,{withFileTypes:!0})}catch(r){if(r?.code==="ENOENT")return[];throw r}let i=[];for(let r of n.sort((a,o)=>a.name.localeCompare(o.name))){if(!r.isDirectory()||!yf(r.name,t.category))continue;let a=zt.join(e.root,r.name),o=await Mq(t,a);o&&i.push(o)}return i.sort((r,a)=>a.createdAt.localeCompare(r.createdAt)||a.id.localeCompare(r.id))}async function $l(t,e,n){if(Ux(n.id,t.category),n.category!==t.category||!Aq(n.scope,t.scope))throw new Error(`Asset metadata does not match library scope/category: ${n.id}`);let i=zt.join(e.root,n.id);if(!Yr(e.root,i))throw new Error(`Invalid asset path for ${n.id}`);await xf(i,{recursive:!0}),await VE(zt.join(i,"asset.json"),n)}async function zq(t,e){await xf(t.root,{recursive:!0});let n={version:1,generatedAt:new Date().toISOString(),assets:e.map(i=>i.id)};await VE(t.index,n)}function Ti(t,e,n){return{fileName:t,reason:e,message:n}}async function Xr(t){let e=BE(t);return await xf(e.inbox,{recursive:!0}),e}async function Lq(t){let e=await Xr(t),n=await bf(t,e);return await zq(e,n),n}async function Lt(t,e){Ux(e,t.category);let n=await Xr(t),i=zt.join(n.root,e);if(!Yr(n.root,i))throw new Error(`Invalid asset path for ${e}`);let r=await Mq(t,i);if(!r)throw new Error(`Asset not found: ${e}`);return r}async function Ol(t){let e=await Xr(t),n=await bf(t,e),i={version:1,generatedAt:new Date().toISOString(),assets:n.map(r=>r.id)};return await VE(e.index,i),i}async function Uq(t){let e=await Xr(t),n=await bf(t,e),i=new Set(n.map(p=>p.id)),r=new Set(n.map(p=>p.file.sha256)),a=[],o=[],s=t.maxFileSizeBytes??Tq,c=t.maxFilesPerRescan??wme,l;try{l=await Rq(e.inbox,{withFileTypes:!0})}catch(p){if(p?.code==="ENOENT")l=[];else throw p}let u=l.sort((p,f)=>p.name.localeCompare(f.name));for(let p=0;p<u.length;p++){let f=u[p];if(p>=c){o.push(Ti(f.name,"maxFileCount","rescan file count limit exceeded"));continue}if(f.name.startsWith(".")){o.push(Ti(f.name,"hidden","hidden or system file"));continue}if(f.isSymbolicLink()){o.push(Ti(f.name,"symlink","symlink files are not followed"));continue}if(f.isDirectory()){o.push(Ti(f.name,"nestedDirectory","nested directories are not scanned"));continue}if(!f.isFile()){o.push(Ti(f.name,"unsupportedType","unsupported inbox entry type"));continue}let m=$q(f.name,t.category);if(!m){o.push(Ti(f.name,"unsupportedType",`unsupported ${t.category} extension`));continue}let g=zt.join(e.inbox,f.name),h=await Sme(g);if(h.size>s){o.push(Ti(f.name,"oversized","asset file is larger than the configured limit"));continue}let v=await Pq(g);if(!ZE(f.name,t.category,v)){o.push(Ti(f.name,"invalidSignature","file signature does not match the extension"));continue}let x=Oq(v);if(r.has(x)){o.push(Ti(f.name,"duplicate","asset content already exists in Asset Library"));continue}let _=Dq(t,i);i.add(_),r.add(x);let I=zt.join(e.root,_),w=`original${m.canonicalExt}`;await xf(I,{recursive:!0}),await Eq(g,zt.join(I,w));let D=new Date(Bx(t)).toISOString(),M={version:1,id:_,category:t.category,scope:t.scope,status:"localOnly",displayName:Nq(f.name),description:"",source:{kind:"generated",originalPath:vf(t.projectSyncRoot,g)},file:{original:w,preview:null,mimeType:m.mimeType,sha256:x,sizeBytes:h.size,width:null,height:null,durationMs:null},roblox:{uploaded:!1},usage:{lastScannedAt:null,scanSource:null,references:[]},createdAt:D,updatedAt:D};await $l(t,e,M),a.push(M)}let d=await bf(t,e);return await zq(e,d),{assets:d,adopted:a,skipped:o,adoptedCount:a.length,skippedCount:o.length}}async function Fq(t){let e=await Xr(t),n=$q(t.originalFileName,t.category);if(!n)throw new Error(`Unsupported ${t.category} extension for Asset Library export`);let i=t.maxFileSizeBytes??Tq;if(t.content.length>i)throw new Error("asset file is larger than the configured limit");if(!ZE(t.originalFileName,t.category,t.content))throw new Error("file signature does not match the extension");let r=await bf(t,e),a=Oq(t.content),o=r.find(h=>h.file.sha256===a);if(o)return{asset:o,deduplicated:!0};let s=new Set(r.map(h=>h.id)),c=Dq(t,s),l=zt.join(e.root,c);if(!Yr(e.root,l))throw new Error(`Invalid asset path for ${c}`);let u=`original${n.canonicalExt}`;await xf(l,{recursive:!0}),await qx(zt.join(l,u),t.content);let d=null;if(t.preview){let h=jq(t.preview);d=h.fileName,await qx(zt.join(l,h.fileName),h.content)}let p=new Date(Bx(t)).toISOString(),f=t.roblox??{uploaded:!1},m=f.uploaded&&f.assetId?"uploaded":"localOnly",g={version:1,id:c,category:t.category,scope:t.scope,status:m,displayName:t.displayName?.trim()||Nq(t.originalFileName),description:t.description??"",source:{...t.source,originalPath:vf(t.projectSyncRoot,zt.join(l,u))},file:{original:u,preview:d,mimeType:n.mimeType,sha256:a,sizeBytes:t.content.length,width:null,height:null,durationMs:null},roblox:f,usage:{lastScannedAt:null,scanSource:null,references:[]},...t.rbxm?{rbxm:t.rbxm}:{},createdAt:p,updatedAt:p};return await $l(t,e,g),await Ol(t),{asset:g,deduplicated:!1}}async function qq(t){let e=await Xr(t),n=await Lt(t,t.assetId),i=jq(t.preview),r=Fx({...t,relativeFileName:i.fileName});await qx(r,i.content);let a={...n,file:{...n.file,preview:i.fileName},...n.rbxm&&t.rbxmThumbnail?{rbxm:{...n.rbxm,thumbnail:t.rbxmThumbnail}}:{},updatedAt:new Date(Bx(t)).toISOString()};return await $l(t,e,a),await Ol(t),{asset:a}}async function Bq(t,e,n){let i=await Xr(t),r=await Lt(t,e),a={...r,displayName:typeof n.displayName=="string"?n.displayName:r.displayName,description:typeof n.description=="string"?n.description:r.description,source:{...r.source,...n.source?.agent!==void 0?{agent:n.source.agent}:{},...n.source?.contextId!==void 0?{contextId:n.source.contextId}:{},...n.source?.prompt!==void 0?{prompt:n.source.prompt}:{}},updatedAt:new Date().toISOString()};return await $l(t,i,a),await Ol(t),a}async function Hq(t,e,n){let i=await Xr(t),a={...await Lt(t,e),usage:n,updatedAt:new Date().toISOString()};return await $l(t,i,a),await Ol(t),a}async function Zq(t,e){let n=await Xr(t);await Lt(t,e);let i=zt.join(n.root,e);if(!Yr(n.root,i))throw new Error(`Invalid asset path for ${e}`);return await _me(i,{recursive:!0}),await Ol(t),{assetId:e,removed:1}}async function Ha(t){let e=await Xr(t);return await $l(t,e,t.asset),await Ol(t),t.asset}async function Dl(t){let e=await Lt(t,t.assetId);return Fx({...t,relativeFileName:e.file.original})}async function Vq(t){let e=await Lt(t,t.assetId);return Fx({...t,relativeFileName:e.file.preview??e.file.original})}var Pme="https://create.roblox.com/dashboard/creations/store",Rme="manage_assets_import_rbxm",GE="manage_assets_generate_thumbnail",Eme="manage_assets_review_model";var KE=new Set([Rme,GE]),JE=new Set(["manage_assets_export_selection_rbxm","manage_assets_export_path_rbxm",Eme]),Tme=new Set(["model","animation"]);function Qe(t){return t&&typeof t=="object"?t:null}function Ame(t){if(typeof t!="string"||!Tme.has(t))throw new Error(`Unsupported Asset Library .rbxm round-trip category: ${String(t??"(missing)")}`);return t}function $me(t){if(typeof t=="number"&&Number.isInteger(t)&&t>=0)return t;if(typeof t=="string"&&t.trim().length>0){let e=Number.parseInt(t,10);if(Number.isInteger(e)&&e>=0)return e}return null}function Wq(t,e){for(let n of t.pluginClients.values())if(!(typeof n.placeId!="number"||!Number.isFinite(n.placeId))&&!(e!==void 0&&n.placeId!==e))return{placeId:n.placeId,...n.placeName?{placeName:n.placeName}:{}};return null}function YE(t,e){let n=mt(t.config.dataDir),i=Ame(e.category),r=typeof e.scope=="string"?e.scope:"place",a=typeof e.assetLibraryAssetId=="string"&&e.assetLibraryAssetId.length>0?e.assetLibraryAssetId:void 0;if(r==="shared")return{projectSyncRoot:n,scope:{kind:"shared"},category:i,...a?{assetId:a}:{}};if(r!=="place")throw new Error(`Invalid Asset Library scope: ${r}`);let o=$me(e.placeId),s=t.syncController?.getDefaultRuntimePlaceId()??null,c=o??s??Wq(t)?.placeId??null;if(c===null)throw new Error("No placeId is available for Asset Library .rbxm round-trip.");let l=Wq(t,c);return{projectSyncRoot:n,scope:{kind:"place",placeId:c,...l?.placeName?{placeName:l.placeName}:{}},category:i,...a?{assetId:a}:{}}}function Ome(t){if(kme.extname(t.file.original).toLowerCase()!==".rbxm")throw new Error(`Asset Library Studio round-trip supports original.rbxm only. Unsupported original file: ${t.file.original}`)}function Dme(t,e){if(typeof t!="string"||t.trim().length===0)throw new Error(`${e} is missing`);return Buffer.from(t,"base64")}function Nme(t,e){let n=Qe(e),r={kind:n?.kind==="generation"||typeof t.prompt=="string"?"generated":"studioExport",originalPath:"studio:selection"};if(n){let a=typeof n.path=="string"?n.path:typeof n.kind=="string"?n.kind:void 0;a&&(r.originalPath=`studio:${a}`);let o=ge(n.prompt,1e3);o&&(r.prompt=o)}if(!r.prompt){let a=ge(t.prompt,1e3);a&&(r.prompt=a)}return typeof t.contextId=="string"&&(r.contextId=t.contextId),r}function Yq(t){let e=Qe(t);if(!e)return;let n={};typeof e.width=="number"&&(n.width=e.width),typeof e.height=="number"&&(n.height=e.height),typeof e.source=="string"&&(n.source=e.source),typeof e.error=="string"&&(n.error=e.error);let i=_f(e.attempts);return i.length>0&&(n.attempts=i),Object.keys(n).length>0?n:void 0}function ge(t,e){return typeof t!="string"?null:t.slice(0,e)}function jme(t){if(typeof t!="string")return null;let e=t.trim();return/^\d+$/.test(e)?e:null}function Gq(t){return`rbxassetid://${t}`}function Kq(t){return`${Pme}/${t}/configure`}function Jq(t){return`assets/${t}`}function rr(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Xq(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.name,256),r=ge(n.className,128),a=ge(n.path,512);return i===null||r===null||a===null?[]:[{name:i,className:r,path:a}]}):[]}function Mme(t){let e=Qe(t);if(!e)return{};let n={};for(let[i,r]of Object.entries(e).slice(0,100))typeof r!="number"||!Number.isFinite(r)||r<0||(n[i.slice(0,128)]=Math.floor(r));return n}function zme(t){return Array.isArray(t)?t.slice(0,200).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.path,512),r=ge(n.property,128),a=ge(n.value,1024);if(i===null||r===null||a===null)return[];let o=ge(n.assetId,64);return[{path:i,property:r,value:a,...o?{assetId:o}:{}}]}):[]}function _f(t){return Array.isArray(t)?t.slice(0,8).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.method,80),r=n.status==="success"||n.status==="failed"||n.status==="skipped"?n.status:null;if(i===null||r===null)return[];let a=ge(n.message,512);return[{method:i,status:r,...a?{message:a}:{}}]}):[]}function Lme(t,e){let n=t.thumbnailMode==="auto"?"auto":"none";if(n==="none")return{mode:n,status:"skipped",message:"Thumbnail generation disabled"};let i=Yq(e),r=Qe(e),a=typeof r?.pngBase64=="string"&&r.pngBase64.length>0,o=typeof r?.base64Rgba=="string"&&r.base64Rgba.length>0&&r.format==="rgba8"&&typeof r.width=="number"&&typeof r.height=="number";if(i&&(a||o)){let s=rr(i.width),c=rr(i.height),l=_f(r?.attempts);return{mode:n,status:"generated",...s!==void 0?{width:s}:{},...c!==void 0?{height:c}:{},...typeof i.source=="string"?{source:i.source.slice(0,128)}:{},...l.length>0?{attempts:l}:{}}}if(i&&typeof i.error=="string"){let s=_f(Qe(e)?.attempts);return{mode:n,status:"failed",message:i.error.slice(0,512),...s.length>0?{attempts:s}:{}}}return{mode:n,status:"skipped",message:"Thumbnail was not returned"}}function Ume(t,e){let n=Qe(t);if(!n)return e;let i=n.mode==="auto"||n.mode==="none"?n.mode:e.mode,r=n.status==="generated"||n.status==="skipped"||n.status==="failed"?n.status:e.status,a=ge(n.message,512),o=rr(n.width),s=rr(n.height),c=ge(n.source,128),l=_f(n.attempts);return{mode:i,status:r,...a?{message:a}:{},...o!==void 0?{width:o}:{},...s!==void 0?{height:s}:{},...c?{source:c}:{},...l.length>0?{attempts:l}:{}}}function WE(t,e=0){if(e>3)return;if(typeof t=="string")return t.slice(0,512);if(typeof t=="boolean")return t;if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(Array.isArray(t))return t.slice(0,50).flatMap(r=>{let a=WE(r,e+1);return a===void 0?[]:[a]});let n=Qe(t);if(!n)return;let i={};for(let[r,a]of Object.entries(n).slice(0,50)){let o=WE(a,e+1);o!==void 0&&(i[r.slice(0,128)]=o)}return i}function Fme(t){let e=Qe(t),n=rr(e?.x),i=rr(e?.y),r=rr(e?.z);if(!(n===void 0||i===void 0||r===void 0))return{x:n,y:i,z:r}}function qme(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=n.severity==="info"||n.severity==="warning"||n.severity==="error"?n.severity:null,r=ge(n.category,80),a=ge(n.code,120),o=ge(n.path,512),s=ge(n.message,512);if(!i||r===null||a===null||o===null||s===null)return[];let c=ge(n.suggestion,512);return[{severity:i,category:r,code:a,path:o,message:s,...c?{suggestion:c}:{}}]}):[]}function Bme(t){let e=Qe(t);if(!e)return;let n=e.readiness==="ready"||e.readiness==="review"||e.readiness==="blocked"?e.readiness:null;if(!n)return;let i=WE(e.summary),r=ge(e.reviewedAt,64),a=Xq(e.roots);return{readiness:n,...r?{reviewedAt:r}:{},...a.length>0?{roots:a}:{},summary:Qe(i)??{},findings:qme(e.findings)}}function Hme(t){let e=Qe(t);if(!e)return;let n={};for(let[i,r]of Object.entries(e).slice(0,16))typeof r=="string"&&(n[i.slice(0,128)]=r.slice(0,256)),typeof r=="number"&&Number.isFinite(r)&&(n[i.slice(0,128)]=r),typeof r=="boolean"&&(n[i.slice(0,128)]=r);return Object.keys(n).length>0?n:void 0}function Zme(t){let e=Qe(t);if(!e)return;let n=ge(e.provider,120);if(!n)return;let i=ge(e.generatedAt,64),r=ge(e.prompt,1e3),a=e.schemaMode==="predefined"||e.schemaMode==="custom"?e.schemaMode:void 0,o=e.predefinedSchema==="Body1"||e.predefinedSchema==="Car5"?e.predefinedSchema:void 0,s=Array.isArray(e.schemaGroups)?e.schemaGroups.slice(0,50).flatMap(f=>{let m=ge(f,120);return m?[m]:[]}):void 0,c=Fme(e.requestedSize),l=rr(e.maxTriangles),u=ge(e.targetParent,512),d=ge(e.path,512),p=Hme(e.metadata);return{provider:n,...i?{generatedAt:i}:{},...r?{prompt:r}:{},...a?{schemaMode:a}:{},...o?{predefinedSchema:o}:{},...s&&s.length>0?{schemaGroups:s}:{},...c?{requestedSize:c}:{},...l!==void 0?{maxTriangles:Math.floor(l)}:{},...typeof e.generateTextures=="boolean"?{generateTextures:e.generateTextures}:{},...u?{targetParent:u}:{},...d?{path:d}:{},...p?{metadata:p}:{}}}function Vme(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.path,512),r=n.assetType==="Mesh"||n.assetType==="Image"||n.assetType==="Model"?n.assetType:null,a=n.status==="uploaded"||n.status==="failed"?n.status:null;if(i===null||r===null||a===null)return[];let o=ge(n.assetId,64),s=ge(n.assetUri,128),c=n.creatorType==="user"||n.creatorType==="group"?n.creatorType:void 0,l=ge(n.creatorId,64),u=ge(n.sourceProperty,128),d=ge(n.uploadedAt,64),p=ge(n.message,512);return[{path:i,assetType:r,status:a,...o?{assetId:o}:{},...s?{assetUri:s}:{},...c?{creatorType:c}:{},...l?{creatorId:l}:{},...u?{sourceProperty:u}:{},...d?{uploadedAt:d}:{},...p?{message:p}:{}}]}):[]}function Wme(t){let e=Qe(t);if(!e||e.uploaded!==!0)return;let n=jme(e.assetId);if(!n)return;let i=ge(e.uploadedAt,64)??new Date().toISOString(),r=e.creatorType==="user"||e.creatorType==="group"?e.creatorType:void 0,a=ge(e.creatorId,64);return{uploaded:!0,assetId:n,assetUri:Gq(n),assetWebUrl:Kq(n),remotePath:Jq(n),uploadedAt:i,uploadAttempts:[{startedAt:i,finishedAt:i,status:"uploaded",assetRole:"primary",...r?{creatorType:r}:{},...a?{creatorId:a}:{},assetId:n,assetUri:Gq(n),assetWebUrl:Kq(n),remotePath:Jq(n)}]}}function Gme(t){let e=Qe(t.value),n=Xq(e?.roots),i=Mme(e?.classCounts),r=zme(e?.resourceReferences),a=Bme(e?.review),o=Zme(e?.generation),s=Vme(e?.studioUploads),c=rr(e?.exportedCount)??rr(t.exportedCount)??n.length;return{exportedCount:Math.max(0,Math.floor(c)),roots:n,classCounts:i,resourceReferences:r,thumbnail:Ume(e?.thumbnail,t.fallbackThumbnail),...a?{review:a}:{},...o?{generation:o}:{},...s.length>0?{studioUploads:s}:{}}}function Kme(t){return t.length>=8&&t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71&&t[4]===13&&t[5]===10&&t[6]===26&&t[7]===10}function Qq(t){let e=Qe(t);if(!e)return;let n=null;if(typeof e.pngBase64=="string"&&e.pngBase64.length>0?n=Buffer.from(e.pngBase64,"base64"):typeof e.base64Rgba=="string"&&e.base64Rgba.length>0&&e.format==="rgba8"&&typeof e.width=="number"&&typeof e.height=="number"&&(n=Buffer.from(bq(e.base64Rgba,e.width,e.height),"base64")),!!n){if(!Kme(n))throw new Error("Thumbnail payload is not a valid PNG image.");return{fileName:"thumbnail.png",content:n,mimeType:"image/png"}}}function Jme(t,e){let n=e instanceof Error?e.message:String(e);return t.thumbnail.status!=="generated"?t:{...t,thumbnail:{...t.thumbnail,status:"failed",message:`Thumbnail payload could not be stored: ${n}`.slice(0,512)}}}async function eB(t){if(!KE.has(t.command))return t.params;let e=YE(t.ctx,t.params);if(!e.assetId)throw new Error("assetLibraryAssetId is required for Asset Library .rbxm round-trip.");let n=await Lt(e,e.assetId);Ome(n);let i=await Dl({...e,assetId:n.id}),r=await Ime(i);return{...t.params,__assetLibraryRbxmBase64:r.toString("base64"),__assetLibraryOriginalFile:n.file.original}}async function tB(t){if(!JE.has(t.command)||!t.result.success)return t.result;let e=Qe(t.result.data);if(!e||typeof e.rbxmBase64!="string"||e.rbxmBase64.trim().length===0)return t.result;let n=YE(t.ctx,t.params),i=Dme(e.rbxmBase64,"Asset Library .rbxm export payload"),r=typeof t.params.displayName=="string"?t.params.displayName:void 0,a=typeof t.params.description=="string"?t.params.description:void 0,o=`${r?.trim()||"studio-export"}.rbxm`,s,c=null;try{s=Qq(e.thumbnail)}catch(f){c=f,s=void 0}let l=Gme({value:e.rbxm,exportedCount:e.exportedCount,fallbackThumbnail:Lme(t.params,e.thumbnail)});c&&(l=Jme(l,c));let u=Wme(e.roblox),d=await Fq({projectSyncRoot:n.projectSyncRoot,scope:n.scope,category:n.category,originalFileName:o,content:i,...r!==void 0?{displayName:r}:{},...a!==void 0?{description:a}:{},source:Nme(t.params,e.source),...s?{preview:s}:{},rbxm:l,...u?{roblox:u}:{}}),p=Yq(e.thumbnail);return{...t.result,data:{asset:d.asset,deduplicated:d.deduplicated,...typeof e.byteLength=="number"?{byteLength:e.byteLength}:{},...typeof e.exportedCount=="number"?{exportedCount:e.exportedCount}:{},...e.source!==void 0?{source:e.source}:{},...p?{thumbnail:p}:{}}}}async function nB(t){if(!t.result.success)return t.result;let e=Qe(t.result.data),n=Qe(e?.thumbnail),i;try{i=Qq(n)}catch(d){return{...t.result,success:!1,error:d instanceof Error?d.message:String(d)}}if(!n||!i)return{...t.result,success:!1,error:typeof n?.error=="string"?n.error:"Thumbnail payload is missing from Asset Library thumbnail generation result."};let r=rr(n.width),a=rr(n.height),o=ge(n.source,128),s=_f(n.attempts),c={mode:"auto",status:"generated",...r!==void 0?{width:r}:{},...a!==void 0?{height:a}:{},...o?{source:o}:{},...s.length>0?{attempts:s}:{}},l=YE(t.ctx,t.params);if(!l.assetId)throw new Error("assetLibraryAssetId is required for Asset Library thumbnail generation.");let u=await qq({projectSyncRoot:l.projectSyncRoot,scope:l.scope,category:l.category,assetId:l.assetId,preview:i,rbxmThumbnail:c});return{...t.result,data:{asset:u.asset,...r!==void 0?{width:r}:{},...a!==void 0?{height:a}:{},...o?{source:o}:{}}}}function Yme(t){if(t===null||typeof t!="object")return;let e=t.proFallback;if(e===null||typeof e!="object")return;let n=e;if(typeof n.executedCommand!="string")return;let i=Array.isArray(n.alternatives)?n.alternatives.filter(r=>typeof r=="string"):void 0;return{executedCommand:n.executedCommand,...typeof n.requestedCommand=="string"?{requestedCommand:n.requestedCommand}:{},...i?{alternatives:i}:{}}}var Xme=/^Pro action '[^']+' is blocked in Basic mode\. Basic fallback '([^']+)' failed: (.*)$/s,Qme=/^Pro action '[^']+' is blocked in Basic mode\.(?! Basic fallback ')/,ege=/instance not found|not found in|parent not found/,tge=/is required|missing required/,nge=/unknown action|unknown command/,rge=/must be|invalid|cannot/;function ige(t){let e=Xme.exec(t);return e?{fallbackCommand:e[1],reason:e[2]}:null}function age(t){return Qme.test(t)}function oge(t){let e=t.toLowerCase();return ege.test(e)?"not_found":tge.test(e)?"missing_param":nge.test(e)?"unknown_action":rge.test(e)?"validation":"other"}function XE(t){return t.errorType==="bridge_error"||t.errorType==="command_timeout"||t.errorType==="plugin_runtime"||t.errorType==="exception"||t.errorType==="device_blocked"||t.failureOrigin==="bridge"||t.failureOrigin==="plugin_runtime"||t.failureOrigin==="server_exception"||t.failureOrigin==="product_bug"||t.failureOrigin==="unknown"||t.recoverability==="retry"||t.recoverability==="wait_connection"||t.recoverability==="unknown"?"error":"warning"}function Nl(t){if(t.resultSuccess){let e=Yme(t.resultData);return e?{kind:"success_fallback",fallbackCommand:e.executedCommand,...e.alternatives?{alternatives:e.alternatives}:{}}:{kind:"success_ok"}}if(!t.resultError)return{kind:"error"};if(t.tier==="pro"){let e=ige(t.resultError);if(e)return{kind:"blocked_fallback_failed",fallbackCommand:e.fallbackCommand,blockedDetail:oge(e.reason)};if(age(t.resultError))return{kind:"blocked_unsupported"}}return t.failureClassification?{kind:XE(t.failureClassification)}:{kind:"error"}}function we(t,e,n,i,r={}){return{errorType:t,errorDetail:e,failureOrigin:n,recoverability:i,...r}}function sge(t){let e=t.toLowerCase();return/^\s*compilation error:/.test(e)?we("execution_failed","compile_error","agent_request","code_fix",{validationStage:"plugin_handler"}):/^\s*result too large:/.test(e)?we("execution_failed","result_too_large","agent_request","code_fix",{validationStage:"plugin_handler"}):/^\s*execution timed out after/.test(e)?we("execution_failed","execution_timeout","agent_request","code_fix",{validationStage:"plugin_handler"}):/potentially dangerous infinite loop|blocked in sandbox|access to .* is blocked|forbidden|not allowed|cannot access/.test(e)?we("execution_failed","blocked_source","roblox_policy","code_fix",{validationStage:"plugin_handler"}):null}function rB(t){let e=t.toLowerCase();return/upstream_server_down/.test(e)?we("bridge_error","upstream_down","bridge","wait_connection"):/^http [45]\d\d/.test(e)?we("bridge_error","http_error","bridge","retry"):/duplicate request\s*id/.test(e)?we("bridge_error","duplicate_request_id","bridge","code_fix"):/timeout/.test(e)?we("command_timeout","timeout","bridge","retry"):/econnrefused|socket hang up|econnreset|epipe|network/.test(e)?we("bridge_error","connection","bridge","wait_connection"):/abort/.test(e)?we("command_timeout","aborted","bridge","retry"):/runtime error|traceback|attempt to/.test(e)?we("plugin_runtime","runtime_error","plugin_runtime","code_fix"):/created instance, but failed to set \d+ propert/.test(e)?we("execution_failed","property_apply_failed","agent_request","fix_params",{validationStage:"plugin_handler",partialSuccess:"true"}):/failed to set property/.test(e)?we("execution_failed","property_apply_failed","agent_request","fix_params",{validationStage:"plugin_handler"}):/parent(?: instance)? not found/.test(e)?we("execution_failed","parent_not_found","agent_request","fix_params",{validationStage:"plugin_handler"}):/(?:instance|path|root|source instance|ancestor instance) not found|target\s+(?:path\s+)?(?:['"`][^'"`]+['"`]\s+)?not found|not found in|no synced file found for instance/.test(e)?we("execution_failed","not_found","user_project_state","fix_params",{validationStage:"plugin_handler"}):/is required|missing required/.test(e)?we("execution_failed","missing_param","agent_request","fix_params",{validationStage:"schema"}):/invalid classname|invalid class/.test(e)?we("execution_failed","invalid_class","agent_request","fix_params",{validationStage:"plugin_handler"}):/unknown action|unknown command/.test(e)?we("execution_failed","unknown_action","agent_request","fix_params",{validationStage:"dispatcher"}):/failed to insert asset/.test(e)?we("execution_failed","asset_error","roblox_policy","fix_params",{validationStage:"roblox_api"}):/failed to read property|property access denied/.test(e)?we("execution_failed","property_error","agent_request","fix_params",{validationStage:"plugin_handler"}):/forbidden (?:path|parent path)|exceeds (?:total lines|max(?:imum)?(?: length)?)|is not (?:a|an) /.test(e)?we("execution_failed","validation","agent_request","fix_params",{validationStage:"plugin_handler"}):/sync controller not available|project sync is not initialized|no active sync place|not found in sync cache/.test(e)?we("execution_failed","sync_not_ready","user_project_state","wait_connection",{validationStage:"preflight"}):/cannot capture edit-mode screenshot while a playtest is active|play-mode screenshot capture is not supported/.test(e)?we("execution_failed","unsupported_context","roblox_policy","no_retry",{validationStage:"preflight"}):/editableimage api is not enabled|allow mesh \/ image apis|allow http requests/.test(e)?we("execution_failed","feature_disabled","roblox_policy","no_retry",{validationStage:"preflight"}):/must be|invalid|cannot/.test(e)?we("execution_failed","validation","agent_request","fix_params",{validationStage:"plugin_handler"}):we("execution_failed","other","unknown","unknown")}function jl(t,e){if(t==="execute_luau"){let i=sge(e);if(i)return i}let n=rB(e);return t==="execute_luau"&&n.errorDetail==="runtime_error"&&/^\s*runtime error:/i.test(e)?we("execution_failed","runtime_error","agent_request","code_fix"):n}function iB(t){let n=(t instanceof Error?t.message:String(t)).toLowerCase();return/timeout/.test(n)?we("command_timeout","timeout","bridge","retry"):/econnrefused|socket hang up|network|econnreset|epipe/.test(n)?we("bridge_error","connection","bridge","wait_connection"):/eaddrinuse/.test(n)?we("bridge_error","port_in_use","bridge","no_retry"):we("exception","unexpected","server_exception","code_fix")}Vx();import{randomBytes as fge}from"node:crypto";var mge=["manage_ui_create_tree","manage_ui_update","manage_ui_delete"],pB=["manage_ui_preview","manage_ui_check"],gge=["game_genre","ui_role","style_family","layout_family","device_policy","safe_area_policy","existing_ui_strategy"];function iT(t){return t&&typeof t=="object"?t:void 0}function nT(t){return typeof t=="number"&&Number.isFinite(t)?t:0}function Wx(t){let e=iT(t);if(!e)return;let n={};for(let i of gge){let r=e[i];typeof r=="string"&&r.trim().length>0&&(n[i]=r)}return Object.keys(n).length>0?n:void 0}function rT(t){let e=Wx(t.qualityPlanSummary);if(e)return e;let n=iT(t.contextSummary),i=Wx(n?.qualityPlanSummary);if(i)return i;let r=Wx(n?.qualityPlan);if(r)return r;let a=Wx(n?.quality_plan);if(a)return a}function fB(t,e){return e?{...t??{},...e}:t}function hge(t){return typeof t=="string"?{snapshotId:t}:t&&typeof t=="object"?{snapshotId:typeof t.snapshotId=="string"?t.snapshotId:null,...t.designCheckSummary!==void 0&&{designCheckSummary:t.designCheckSummary},...t.capturedAt!==void 0&&{capturedAt:t.capturedAt}}:{snapshotId:null}}function mB(t,e,n,i,r){if(!e)return;let a=nT(e.priority_high),o=nT(e.priority_medium),s=nT(e.priority_low),c=typeof e.total=="number"&&Number.isFinite(e.total)?e.total:a+o+s,l=n??(typeof e.target=="string"?e.target:void 0);return{source:t,...l!==void 0&&{targetPath:l},...typeof i=="string"&&{snapshotId:i},...r!==void 0&&{capturedAt:r},priority_high:a,priority_medium:o,priority_low:s,total:c}}function gB(t,e){if(!e)return t;if(!t)return e;let n=t.targetPath===e.targetPath?t.targetPath:void 0,i=t.snapshotId===e.snapshotId?t.snapshotId:void 0;return{source:e.source,...n!==void 0&&{targetPath:n},...i!==void 0&&{snapshotId:i},...e.capturedAt!==void 0&&{capturedAt:e.capturedAt},priority_high:t.priority_high+e.priority_high,priority_medium:t.priority_medium+e.priority_medium,priority_low:t.priority_low+e.priority_low,total:t.total+e.total}}function yge(t){let e=iT(t);if(e)for(let n of["userMessage","intent","expectedBehavior"]){let i=e[n];if(typeof i=="string"&&i.trim().length>0)return i.trim().slice(0,80)}}function vge(){return{source:"unavailable",priority_high:0,priority_medium:0,priority_low:0,total:0}}function hB(t){let e=t.now??Date.now,n=null,i=null,r=u=>`${u}_${e()}_${fge(3).toString("hex")}`,a=()=>{i&&(clearTimeout(i),i=null)},o=()=>{a(),i=setTimeout(()=>{c("idle_timeout")},t.idleMs)},s=async u=>{try{return hge(await t.capturePreview(u))}catch{return{snapshotId:null}}},c=async u=>{if(!n)return;a();let d=n;n=null;let p={},f;for(let h of d.affectedPaths)if(d.afterSnapshotsPathPolicy[h]==="skip")p[h]=null;else{let v=await s(h);p[h]=v.snapshotId,f=gB(f,mB("after_snapshot",v.designCheckSummary,h,v.snapshotId,v.capturedAt))}let m=f??d.latestDesignCheckSummary??vge(),g={requestId:d.requestId,...d.contextId!==void 0&&{contextId:d.contextId},...d.label!==void 0&&{label:d.label},startedAt:d.startedAtIso,closedAt:new Date(e()).toISOString(),closeReason:u,ok:d.ok,affectedPaths:Array.from(d.affectedPaths).sort(),mutationCount:d.mutationCount,beforeSnapshots:d.beforeSnapshots,afterSnapshots:p,childMutationIds:d.childMutationIds,...d.qualityPlanSummary!==void 0&&{qualityPlanSummary:d.qualityPlanSummary},postChangeDesignCheckSummary:m};await lB(t.placeDir,g)},l=u=>({requestId:r("req"),contextId:u.contextId,label:yge(u.contextSummary),startedAtIso:new Date(e()).toISOString(),startedAtMs:e(),affectedPaths:new Set,beforeSnapshots:{},afterSnapshotsPathPolicy:{},childMutationIds:[],mutationCount:0,ok:!0,qualityPlanSummary:rT(u),latestDesignCheckSummary:void 0,pendingMutation:void 0});return{async beforeMutation(u){if(pB.includes(u.command)){if(n){let p=r("mut");n.qualityPlanSummary=fB(n.qualityPlanSummary,rT(u)),n.pendingMutation={mutationId:p,startedMs:e(),args:u}}return}if(!mge.includes(u.command))return;n&&n.contextId!==u.contextId?await c("context_change"):n&&a(),n||(n=l(u)),n.qualityPlanSummary=fB(n.qualityPlanSummary,rT(u)),u.targetPath&&!(u.targetPath in n.beforeSnapshots)&&(n.affectedPaths.add(u.targetPath),u.command==="manage_ui_create_tree"?n.beforeSnapshots[u.targetPath]=null:n.beforeSnapshots[u.targetPath]=(await s(u.targetPath)).snapshotId,u.command==="manage_ui_delete"?n.afterSnapshotsPathPolicy[u.targetPath]="skip":u.targetPath in n.afterSnapshotsPathPolicy||(n.afterSnapshotsPathPolicy[u.targetPath]="capture"));let d=r("mut");n.pendingMutation={mutationId:d,startedMs:e(),args:u}},async afterMutation(u){if(!n?.pendingMutation)return;let{mutationId:d,args:p}=n.pendingMutation,f={mutationId:d,requestId:n.requestId,ts:new Date(e()).toISOString(),command:p.command,origin:p.origin,...p.targetPath!==void 0&&{targetPath:p.targetPath},...p.briefId!==void 0&&{briefId:p.briefId},...u.diffSummary!==void 0&&{diffSummary:u.diffSummary},...u.changeDetails!==void 0&&{changeDetails:u.changeDetails},ok:u.ok,...u.error!==void 0&&{error:u.error},durationMs:u.durationMs};if(await uB(t.placeDir,f),n.pendingMutation=void 0,pB.includes(p.command)){n.latestDesignCheckSummary=gB(n.latestDesignCheckSummary,mB("check_results",u.designCheckSummary,p.targetPath,u.snapshotId,u.capturedAt));return}if(n.mutationCount++,n.childMutationIds.push(d),u.ok||(n.ok=!1),!n.contextId){await c("legacy_single");return}o()},async flushNow(){n&&await c("explicit")}}}var DB=100,Xge=12e4,Qge=15e3,NB=new Set(["manage_ui_create_tree","manage_ui_update","manage_ui_delete"]);function ehe(t,e){return`License required for internal command ${t}. ${e??"Activate Pro license to use this feature."}`}var the={Text:{category:"text",label:"\uD14D\uC2A4\uD2B8"},PlaceholderText:{category:"text",label:"\uD50C\uB808\uC774\uC2A4\uD640\uB354"},TextColor3:{category:"color",label:"\uAE00\uC790\uC0C9"},BackgroundColor3:{category:"color",label:"\uBC30\uACBD\uC0C9"},BorderColor3:{category:"color",label:"\uD14C\uB450\uB9AC\uC0C9"},ImageColor3:{category:"color",label:"\uC774\uBBF8\uC9C0\uC0C9"},Size:{category:"size",label:"\uC0AC\uC774\uC988"},TextSize:{category:"size",label:"\uAE00\uC790 \uD06C\uAE30"},Position:{category:"layout",label:"\uC704\uCE58"},AnchorPoint:{category:"layout",label:"\uC575\uCEE4"},Rotation:{category:"layout",label:"\uD68C\uC804"},LayoutOrder:{category:"layout",label:"\uB808\uC774\uC544\uC6C3 \uC21C\uC11C"},Visible:{category:"state",label:"\uD45C\uC2DC \uC0C1\uD0DC"},Active:{category:"state",label:"\uD65C\uC131 \uC0C1\uD0DC"},Interactable:{category:"state",label:"\uC0C1\uD638\uC791\uC6A9 \uC0C1\uD0DC"},Selectable:{category:"state",label:"\uC120\uD0DD \uAC00\uB2A5"},Enabled:{category:"state",label:"\uD65C\uC131\uD654"},Image:{category:"asset",label:"\uC774\uBBF8\uC9C0"},Texture:{category:"asset",label:"\uD14D\uC2A4\uCC98"},SoundId:{category:"asset",label:"\uC0AC\uC6B4\uB4DC"}},nhe={text:"\uD14D\uC2A4\uD2B8",color:"\uCEEC\uB7EC",size:"\uC0AC\uC774\uC988",layout:"\uB808\uC774\uC544\uC6C3",state:"\uC0C1\uD0DC",asset:"\uC5D0\uC14B",property:"\uC18D\uC131"},rhe=Object.entries(Tl).reduce((t,[e,n])=>{for(let i of n.validActions)t[`${e}_${i}`]=e;return t},{});function RB(t){return{toolName:rhe[t]||t,commandName:t}}function EB(t,e){if(typeof t.contextId=="string"||!e||typeof e!="object")return t;let n=e.contextId;return typeof n=="string"?{...t,contextId:n}:t}function Gx(t,e){if(t!=="manage_sync_status_current_place")return e;let{placeId:n,...i}=e;return i}function ihe(t,e){let n=e.routing;return{requestId:t,success:!1,error:e.message,errorCode:e.code,routing:n,data:{routing:n}}}async function ahe(t,e){let n=t.syncController;if(!n)return null;try{let i=e.placeId,r=n.getDefaultRuntimePlaceId(),a=null;if(typeof i=="number"&&Number.isFinite(i))a=i;else if(typeof i=="string"&&i.trim().length>0){let s=Number.parseInt(i,10);Number.isFinite(s)&&(a=s)}if(a===null&&(a=r),a===null||!Number.isFinite(a))return null;let o=a===r?n.getDefaultRuntimePlaceName():null;return typeof o=="string"&&o.length>0?await n.config.resolvePlaceRoot(a,o):n.config.getPlaceRoot(a)}catch{return null}}function ohe(t){let e=t.tree;if(!e||typeof e!="object")return;let n=e,i=typeof n.name=="string"&&n.name.length>0?n.name:void 0;return i?`${typeof n.parent=="string"&&n.parent.length>0?n.parent:"StarterGui"}.${i}`:void 0}function she(t,e){let n=e.targetPath;if(typeof n=="string"&&n.length>0)return n;if(t==="manage_ui_create_tree")return ohe(e)}function che(t){let e=the[t];if(e)return e;let n=t.toLowerCase();return n.includes("color")?{category:"color",label:"\uC0C9\uC0C1"}:t==="Size"||n.endsWith("size")||n.includes("scale")?{category:"size",label:"\uC0AC\uC774\uC988"}:n.includes("position")||n.includes("anchor")||n.includes("rotation")||n.includes("layout")?{category:"layout",label:"\uB808\uC774\uC544\uC6C3"}:n.includes("visible")||n.includes("active")||n.includes("enabled")||n.includes("selectable")||n.includes("interactable")?{category:"state",label:"\uC0C1\uD0DC"}:n.includes("image")||n.includes("texture")||n.includes("sound")||n.includes("asset")?{category:"asset",label:"\uC5D0\uC14B"}:n.includes("text")||n.includes("placeholder")?{category:"text",label:"\uD14D\uC2A4\uD2B8"}:{category:"property",label:t}}function TB(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function lhe(t){if(!t||typeof t!="object")return new Map;let e=t,n=e.changed_properties??e.changedProperties;if(!Array.isArray(n))return new Map;let i=new Map;for(let r of n){if(!r||typeof r!="object")continue;let a=r,o=a.property;if(typeof o!="string"||o.length===0)continue;let s=TB(a,"before"),c=TB(a,"after");i.set(o,{...s&&{before:a.before},...c&&{after:a.after},hasBefore:s,hasAfter:c})}return i}function jB(t,e){let i=t.changes?.properties;if(!i||typeof i!="object")return;let r=lhe(e),a=Object.entries(i).map(([o,s])=>{let c=che(o),l=r.get(o),u={property:o,category:c.category,label:c.label,after:l?.hasAfter?l.after:s};return l?.hasBefore&&(u.before=l.before),u});return a.length>0?a:void 0}function MB(t){if(!t||t.length===0)return;let e=new Map;for(let r of t)e.set(r.category,(e.get(r.category)??0)+1);let i=["text","color","size","layout","state","asset","property"].map(r=>{let a=e.get(r)??0;return a>0?`${nhe[r]} ${a}\uAC1C`:null}).filter(r=>r!==null);return i.length>0?`${i.join(", ")} \uBCC0\uACBD`:void 0}function AB(t,e){if(t==="manage_ui_update"){let n=e.changes,i=MB(jB(e));if(i)return i;let r=n?.properties?Object.keys(n.properties).length:0,a=Array.isArray(n?.addChildren)?n.addChildren.length:0,o=Array.isArray(n?.removeChildren)?n.removeChildren.length:0;return`${r} props, +${a}, -${o}`}if(t==="manage_ui_create_tree")return"tree \uC0DD\uC131";if(t==="manage_ui_delete")return"\uC81C\uAC70\uB428"}function Af(t){return t&&typeof t=="object"?t:void 0}function Kx(t,e){let n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:0}function zB(t){let e=Af(t),n=Af(e?.design_check_summary);if(n)return{priority_high:Kx(n,"priority_high"),priority_medium:Kx(n,"priority_medium"),priority_low:Kx(n,"priority_low"),total:Kx(n,"total"),...typeof n.scope=="string"&&{scope:n.scope},...typeof n.target=="string"&&{target:n.target}}}function LB(t){let n=Af(t)?.snapshot_id;return typeof n=="string"?n:null}function $B(t){if(typeof t=="string"&&t.trim().length>0)return t;if(typeof t=="number"&&Number.isFinite(t)){let e=t<1e10?t*1e3:t;return new Date(e).toISOString()}}function UB(t){let e=Af(t),n=Af(e?.meta);return $B(n?.captured_at)??$B(n?.evaluated_at)}function uhe(t,e){let n=t.uiStudioRecorders.get(e);if(n)return n;let i=hB({placeDir:e,idleMs:Qge,capturePreview:async r=>{try{let a=await ir(t,"manage_ui_preview",{targetPath:r},Yx());if(!a.success||!a.data||typeof a.data!="object")return null;let o=zB(a.data),s=UB(a.data);return{snapshotId:LB(a.data),...o!==void 0&&{designCheckSummary:o},...s!==void 0&&{capturedAt:s}}}catch{return null}}});return t.uiStudioRecorders.set(e,i),i}async function dhe(t,e,n){if(!NB.has(e))return null;let i=await ahe(t,n);if(!i)return null;let r=uhe(t,i),a=e,o=typeof n.contextId=="string"?n.contextId:void 0,s=n.contextSummary,c=s!==void 0&&typeof s=="object"?s:void 0,l=she(a,n),u=typeof n.briefId=="string"?n.briefId:void 0,d={command:a,...o!==void 0&&{contextId:o},...c!==void 0&&{contextSummary:c},...l!==void 0&&{targetPath:l},...u!==void 0&&{briefId:u},origin:n.__origin==="dashboard"?"dashboard":"ai"};try{return await r.beforeMutation(d),{recorder:r,command:a,params:n,startedAt:Date.now()}}catch(p){return y.debug("UI Studio recorder beforeMutation \uC2E4\uD328 (\uBB34\uC2DC)",{error:p}),null}}async function OB(t,e){if(t)try{let n=t.command==="manage_ui_update"?jB(t.params,e.data):void 0,i=t.command==="manage_ui_update"?MB(n)??AB(t.command,t.params):AB(t.command,t.params),r=zB(e.data),a=LB(e.data),o=UB(e.data);await t.recorder.afterMutation({ok:e.success,durationMs:Date.now()-t.startedAt,...i!==void 0&&{diffSummary:i},...n!==void 0&&{changeDetails:n},...e.error!==void 0&&{error:e.error},...r!==void 0&&{designCheckSummary:r},...a!==null&&{snapshotId:a},...o!==void 0&&{capturedAt:o}})}catch(n){y.debug("UI Studio recorder afterMutation \uC2E4\uD328 (\uBB34\uC2DC)",{error:n})}}async function Jx(t,e,n,i,r,a){if(!t.historyManager)return;let o=!r.success&&r.error?jl(n,r.error):void 0,s=Nl({resultSuccess:r.success,resultData:r.data,resultError:r.error,tier:zn(n),...o?{failureClassification:o}:{}});if(r.success){let u=s.kind==="success_fallback"&&r.data&&typeof r.data=="object"?{...r.data,outcomeStatus:"fallback",requestedCommand:n,executedCommand:s.fallbackCommand,...s.alternatives?{alternatives:s.alternatives}:{}}:r.data,d=Gx(n,i);r.routing?await t.historyManager.recordSuccess(e,d,u,a,n,void 0,r.routing):await t.historyManager.recordSuccess(e,d,u,a,n);return}if(s.kind==="blocked_unsupported"){await t.historyManager.recordBlockedOutcome(e,Gx(n,i),r.error||"Pro action blocked in Basic mode","blocked_unsupported",{executionTimeMs:a,command:n,...r.routing?{routing:r.routing}:{}});return}if(s.kind==="blocked_fallback_failed"){await t.historyManager.recordBlockedOutcome(e,Gx(n,i),r.error||"Pro action blocked in Basic mode","blocked_fallback_failed",{executionTimeMs:a,command:n,...s.fallbackCommand?{fallbackCommand:s.fallbackCommand}:{},...s.blockedDetail?{blockedDetail:s.blockedDetail}:{},...r.routing?{routing:r.routing}:{}});return}let c=s.kind==="warning"?t.historyManager.recordWarning.bind(t.historyManager):t.historyManager.recordFailure.bind(t.historyManager),l=Gx(n,i);r.routing?await c(e,l,r.error||"Unknown error",a,r.errorCode??o?.errorType.toUpperCase(),n,void 0,r.routing):await c(e,l,r.error||"Unknown error",a,r.errorCode??o?.errorType.toUpperCase(),n)}function cT(t,e,n){let i=t.pendingCommands.get(e)||[];i.length>=DB&&i.shift(),i.push(n),t.pendingCommands.set(e,i)}function phe(t,e){t.globalPendingCommands.length>=DB&&t.globalPendingCommands.shift(),t.globalPendingCommands.push(e)}function FB(t,e,n){let i=Yx(),r={requestId:i,command:e.command,params:e.params,timestamp:Date.now(),queueTimeoutMs:e.queueTimeoutMs,ackedTimeoutMs:e.ackedTimeoutMs,state:vn.QUEUED,targetClientId:n,resolve:()=>{},reject:a=>{y.debug("Auxiliary playtest stop command ended without awaited response",{requestId:i,targetClientId:n,error:a.message})},timeoutId:null};return t.commandQueue.set(i,r),r.timeoutId=setTimeout(()=>{Jb(t,r,r.queueTimeoutMs)},r.queueTimeoutMs),{event:"command",id:i,data:{command:r.command,requestId:i,params:r.params}}}function fhe(t,e,n,i){if(!gf(e.data.command))return;let r=t.commandQueue.get(e.data.requestId);if(!r)return;qB(t,r);let a=n.filter(o=>o.clientId!==i);for(let o of a){let s=FB(t,r,o.clientId);cT(t,o.clientId,s)}a.length>0&&y.info("Fan-out playtest stop command to active plugin clients",{requestId:e.data.requestId,primaryClientId:i,auxiliaryClientIds:a.map(o=>o.clientId)})}function qB(t,e,n){for(let i of gq)setTimeout(()=>{let a=n?[...new Set(n)]:[...new Set(Cn(t).map(o=>o.clientId))];for(let o of a){if(!t.pluginClients.get(o))continue;let c=FB(t,e,o);cT(t,o,c)}y.info("Retry playtest stop command to active plugin clients",{sourceRequestId:e.requestId,delayMs:i,targetClientIds:a}),hl(t)},i).unref?.()}function BB(t){return t==="clientId"||t==="targetAlias"||t==="placeId"}function mhe(t,e,n){if(!n||!gf(e.data.command))return!1;let i=t.commandQueue.get(e.data.requestId)?.routing?.selectionMode;return!BB(i)}function ghe(t,e,n){y.debug("Broadcasting command",{command:e.data.command,requestId:e.data.requestId,targetClientId:n||"all",activeWebsocketClients:Cn(t).length});let i=n;if(n){cT(t,n,e);let r=t.commandQueue.get(e.data.requestId),a=r?.routing?.selectionMode;if(r&&gf(e.data.command)&&BB(a))qB(t,r,[n]);else if(mhe(t,e,n)){let o=Cn(t).sort((s,c)=>c.lastSeen-s.lastSeen);fhe(t,e,o,n),i=void 0}}else phe(t,e);hl(t,i)}async function HB(t,e,n){let i=Date.now(),r="",a={};try{let o=e.body;r=o.command??"",a=o.params||{};let s=o.requestId;if(o.instanceId||(t.serverLastCommandAt=Date.now()),o.instanceId){let m=t.mcpInstances.get(o.instanceId);m&&(m.lastCommandAt=Date.now(),m.lastSeen=m.lastCommandAt)}let c=RB(r),l=typeof o.timeout=="number"&&Number.isFinite(o.timeout)&&o.timeout>0?{timeout:o.timeout}:void 0,u=o.instanceId?t.mcpInstances.get(o.instanceId)?.sessionId??t.sessionId:t.sessionId;if(!r){n.status(400).json({error:"Missing command"});return}if(y.debug("Received execute request",{command:r,requestId:s}),r==="manage_camera_play_screenshot"){let m="manage_camera.play_screenshot is not supported. Screenshot capture is available only in Edit mode via manage_camera.screenshot.",g=Date.now()-i;t.historyManager&&await t.historyManager.recordFailure("manage_camera",a,m,g,"UNSUPPORTED_COMMAND",r),n.json({requestId:s,success:!1,error:m});return}if(r==="get_cached_selection"){let m=a.maxAge,g=mf(t,m!==void 0?m:3e4),h=Date.now()-i;if(!g){let _={requestId:s,success:!0,data:{cached:!1,message:"No cached selection data available. The plugin may not be connected or no selection changes have occurred yet."}};t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,_.data,h,c.commandName),n.json(_);return}let v=Date.now()-g.timestamp,x={cached:!0,selection:g.selection,count:g.count,timestamp:g.timestamp,age:v};t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,x,h,c.commandName),n.json({requestId:s,success:!0,data:x});return}if(r==="get_connection_info"){let m=await Dx(t),g=Date.now()-i;t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,m,g,c.commandName),n.json({requestId:s,success:!0,data:m});return}if(jx(r)==="internal"){if(!t.internalCommandExecutor){n.status(503).json({requestId:s,success:!1,error:`Internal command executor is not initialized for command: ${r}`});return}if(zn(r)==="pro"){if(!t.licenseState){n.status(503).json({requestId:s,success:!1,error:`License state manager is not initialized for internal command: ${r}`});return}let x=await t.licenseState.evaluateProAccess();if(!x.allowed){let _=ehe(r,x.reason),I=Date.now()-i;t.historyManager&&await Jx(t,c.toolName,c.commandName,a,{success:!1,error:_},I),n.json({requestId:s,success:!1,error:_});return}}let m={...a,__sessionId:u},g=await t.internalCommandExecutor(r,m),h=Date.now()-i,v=EB(m,g.data);t.historyManager&&await Jx(t,c.toolName,c.commandName,v,{success:g.success,data:g.data,error:g.error||"Internal command failed"},h),n.json({requestId:s,...g});return}let d=await ir(t,r,a,s,l),p=Date.now()-i,f={...EB(a,d.data),__sessionId:u};t.historyManager&&await Jx(t,c.toolName,c.commandName,f,d,p),n.json(d)}catch(o){let s=Date.now()-i,c=Mn(o);if(t.historyManager&&r){let l=RB(r);await t.historyManager.recordFailure(l.toolName,a,c,s,"EXCEPTION",l.commandName)}y.error("Execute request failed",o),n.status(500).json({success:!1,error:c})}}async function ZB(t,e,n){let i=Date.now(),r=e.body,a=r.action;if(!a||typeof a!="string"){n.status(400).json({success:!1,error:"Missing required field: action"});return}if(!new Set(["get","set","get_all","set_multiple","get_attr","set_attr","get_all_attrs","delete_attr","add_tag","remove_tag","check_tag","get_tags","get_tagged"]).has(a)){n.status(400).json({success:!1,error:`Unsupported action: ${a}`});return}let s=`manage_properties_${a}`,c=Yx(),{action:l,...u}=r;try{t.serverLastCommandAt=Date.now();let d=await ir(t,s,u,c),p=Date.now()-i;t.historyManager&&await Jx(t,"manage_properties",s,u,d,p),n.json(d)}catch(d){let p=Date.now()-i,f=Mn(d);t.historyManager&&await t.historyManager.recordFailure("manage_properties",u,f,p,"EXCEPTION",s),y.error("/api/properties \uC694\uCCAD \uCC98\uB9AC \uC2E4\uD328",d),n.status(500).json({success:!1,error:f})}}async function ir(t,e,n,i,r){if(y.debug("Executing command locally",{command:e,requestId:i}),Q6(t,i)){let d=`Duplicate requestId '${i}' for command '${e}'. Generate a unique requestId for each command.`;return y.warn("Duplicate execute request rejected",{command:e,requestId:i}),{requestId:i,success:!1,error:d}}let a;try{a=Nx(t,Cn(t),n,e)}catch(d){if(d instanceof on)return y.warn("Command target selection failed",{command:e,requestId:i,errorCode:d.code,routing:d.routing}),ihe(i,d);throw d}let o=NB.has(e)?await dhe(t,e,n):null,s=t.config.requestTimeout,c=r?.timeout??Math.max(t.config.requestTimeout,Xge),l=KE.has(e)?await eB({ctx:t,command:e,params:n}):n,u=new Promise((d,p)=>{let f=Date.now(),m={requestId:i,command:e,params:l,timestamp:f,queueTimeoutMs:s,ackedTimeoutMs:c,state:vn.QUEUED,...a.targetClientId?{targetClientId:a.targetClientId}:{},routing:a.routing,resolve:d,reject:p,timeoutId:null};t.commandQueue.set(i,m),Zb(t,a.targetClientId,f),m.timeoutId=setTimeout(()=>{Jb(t,m,s)},s)});return ghe(t,{event:"command",id:Yx(),data:{command:e,requestId:i,params:l}},a.targetClientId),u.then(async d=>{let p=d;if(e==="manage_ui_preview"&&d.success&&d.data)try{let{processPreviewResult:f,resolvePreviewPlaceDirFromCtx:m}=await Promise.resolve().then(()=>(sT(),oT)),g=await m(t,n),h=await f("manage_ui_preview",d.data,g);p={...d,data:h.data,...h.mcpContent?{mcpContent:h.mcpContent}:{}}}catch(f){y.warn("preview post-processing failed",{error:f instanceof Error?f.message:String(f)})}if(e==="manage_ui_check"&&d.success&&d.data&&n.includeVisualAnalysis===!0)try{let{resolvePreviewPlaceDirFromCtx:f}=await Promise.resolve().then(()=>(sT(),oT)),{processCheckResult:m}=await Promise.resolve().then(()=>(PB(),kB)),g=await f(t,n),h=await m("manage_ui_check",d.data,g,n);p={...p,data:h.data}}catch(f){y.warn("check visual post-processing failed",{error:f instanceof Error?f.message:String(f)})}return JE.has(e)?p=await tB({ctx:t,command:e,params:n,result:p}):e===GE&&(p=await nB({ctx:t,params:n,result:p})),p}).then(async d=>(await OB(o,{success:d.success,...d.data!==void 0&&{data:d.data},...d.error!==void 0&&{error:d.error}}),d),async d=>{throw await OB(o,{success:!1,error:Mn(d)}),d})}ce();wi();function Xx(t,e){let n={};e.provider!==void 0&&(n.provider=e.provider),e.tier!==void 0&&(n.tier=e.tier),e.status!==void 0&&(n.status=e.status),e.canUsePro!==void 0&&(n.canUsePro=e.canUsePro),e.cleared===!0&&(n.cleared=!0),rt(t,"license",n)}function ti(t,e,n,i){t.status(e).json({success:!1,error:{code:n,message:i}})}function hhe(t){if(typeof t!="string")return;let e=t.trim().toLowerCase();return e.length>0?e:void 0}function Qx(t,e){if(e==="plugin")return t;let n={...t};return delete n.sessionToken,n}function $f(t,e,n,i){let r=hhe(i??e.query.provider)??"auto";return t.licenseState?.supportsProvider(r)===!1?(ti(n,400,"LICENSE_PROVIDER_UNSUPPORTED",`provider "${r}" is not supported`),null):r}function Of(t,e){return t.licenseState?!0:(ti(e,503,"LICENSE_NOT_INITIALIZED","License system is not initialized"),!1)}function yhe(t){if(!t||typeof t!="object")return!1;let e=t;return(e.canUsePro===!0||e.canUsePro===!1)&&typeof e.status=="string"&&typeof e.checkedAt=="number"}function Df(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=typeof r?.licenseKey=="string"?r.licenseKey:"";if(!a.trim()){ti(n,400,"LICENSE_KEY_REQUIRED","licenseKey is required");return}let o=$f(t,e,n,r?.provider);if(!o)return;let s=typeof r?.pluginClientId=="string"?r.pluginClientId:typeof e.query.clientId=="string"?e.query.clientId:void 0,c=typeof r?.deviceId=="string"?r.deviceId:void 0,l={licenseKey:a,provider:o,clientType:i};s&&(l.pluginClientId=s),c&&(l.deviceId=c),t.licenseState.activateGateway(l).then(u=>{t.analyticsManager?.setTier(u.canUsePro?"pro":"basic"),Xx(t,{provider:u.provider,tier:u.canUsePro?"pro":"basic",status:u.status,canUsePro:u.canUsePro}),n.json(Qx(u,i))}).catch(u=>{y.warn("License activate failed",{error:u instanceof Error?u.message:"unknown_error"}),ti(n,502,"LICENSE_ACTIVATE_FAILED",u instanceof Error?u.message:"License activation failed")})}function Nf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=$f(t,e,n);if(r)try{let a=t.licenseState.getStatus(r);t.analyticsManager?.setTier(a.canUsePro?"pro":"basic"),n.json(Qx(a,i))}catch(a){y.warn("License status check failed",{error:a instanceof Error?a.message:"unknown_error"}),ti(n,502,"LICENSE_STATUS_FAILED",a instanceof Error?a.message:"License status check failed")}}function jf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=$f(t,e,n,r?.provider);if(!a)return;let o={provider:a,clientType:i};i==="plugin"&&typeof r?.sessionToken=="string"&&r.sessionToken.trim()&&(o.sessionToken=r.sessionToken.trim()),typeof r?.pluginClientId=="string"&&(o.pluginClientId=r.pluginClientId),typeof r?.deviceId=="string"&&(o.deviceId=r.deviceId),t.licenseState.refreshGateway(o).then(s=>{t.analyticsManager?.setTier(s.canUsePro?"pro":"basic"),Xx(t,{provider:s.provider,tier:s.canUsePro?"pro":"basic",status:s.status,canUsePro:s.canUsePro}),n.json(Qx(s,i))}).catch(s=>{y.warn("License refresh failed",{error:s instanceof Error?s.message:"unknown_error"}),ti(n,502,"LICENSE_REFRESH_FAILED",s instanceof Error?s.message:"License refresh failed")})}function Mf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=$f(t,e,n,r?.provider);a&&t.licenseState.resetGateway({provider:a,clientType:i}).then(o=>{t.analyticsManager?.setTier("basic"),Xx(t,{provider:o.provider,tier:"basic",status:o.status,canUsePro:o.canUsePro,cleared:!0}),n.json(Qx(o,i))}).catch(o=>{y.warn("License reset failed",{error:o instanceof Error?o.message:"unknown_error"}),ti(n,502,"LICENSE_RESET_FAILED",o instanceof Error?o.message:"License reset failed")})}function lT(t,e,n){if(!Of(t,n))return;let i=e.body,r=$f(t,e,n,i?.provider);if(!r)return;if(i?.clientType!=="plugin"){ti(n,400,"LICENSE_CLIENT_TYPE_INVALID","clientType must be plugin");return}let a=typeof i?.sessionToken=="string"&&i.sessionToken.trim()?i.sessionToken.trim():void 0,o=yhe(i?.snapshot)?i.snapshot:void 0;if(!o&&!a){ti(n,400,"LICENSE_BOOTSTRAP_REQUIRED","snapshot or sessionToken is required");return}let s={provider:r,clientType:"plugin"};o&&(s.snapshot=o),a&&(s.sessionToken=a),t.licenseState.bootstrap(s).then(c=>{t.analyticsManager?.setTier(c.canUsePro?"pro":"basic"),Xx(t,{provider:c.provider,tier:c.canUsePro?"pro":"basic",status:c.status,canUsePro:c.canUsePro}),n.json({ok:!0})}).catch(c=>{y.warn("License bootstrap failed",{error:c instanceof Error?c.message:"unknown_error"}),ti(n,502,"LICENSE_BOOTSTRAP_FAILED",c instanceof Error?c.message:"License bootstrap failed")})}function VB(t){t.app.post("/license/bootstrap",(e,n)=>lT(t,e,n)),t.app.post("/license/activate",(e,n)=>Df(t,e,n,"plugin")),t.app.post("/license/refresh",(e,n)=>jf(t,e,n,"plugin")),t.app.post("/license/reset",(e,n)=>Mf(t,e,n,"plugin")),t.app.get("/license/status",(e,n)=>Nf(t,e,n,"plugin"))}ft();ce();import{promises as e_}from"fs";import uT from"path";function vhe(t){let e=t.config.appDataDir??ot();return uT.join(e,"observability","logs")}async function Fl(t,e,n){let i=e.query.clientId;if(i&&t.pluginClients.has(i)){let r=t.pluginClients.get(i);r.lastSeen=Date.now()}try{let r=e.body;if(!r||!Array.isArray(r.logs)){y.warn("Invalid logs request",{body:r}),n.status(400).json({error:"Invalid request body"});return}let a=vhe(t);await e_.mkdir(a,{recursive:!0});let c=`plugin-${new Date().toISOString().split("T")[0]}.log`,l=uT.join(a,c),u=uT.join(a,"current.log"),d=r.logs.map(p=>`[${new Date(p.timestamp*1e3).toISOString().replace("T"," ").substring(0,19)}] [${p.level}] ${p.message}`).join(`
504
+ `),await ll(g)}catch(g){y.warn("Failed to refresh root representative sourcemap after full sync",{placeId:e,error:g instanceof Error?g.message:String(g)})}this.ctx.startFileWatcherForPlace(r).catch(g=>{y.warn("Failed to start reverse detector after full sync",{placeId:e,error:g instanceof Error?g.message:String(g)}),r.fileWatcher=null}),r.writer.setBootstrapMode(!1),r.writer.appendChangeLog(`FULL_SYNC_COMPLETE instances=${r.instanceCount} scripts=${r.scriptCount}`),r.writer.appendHistory({timestamp:new Date().toISOString(),type:"fullSyncComplete",direction:"forward",source:"studio",path:`place_${e}`,details:`instances:${r.instanceCount} scripts:${r.scriptCount}`}),y.info("Full sync completed",{placeId:e,instanceCount:r.instanceCount,scriptCount:r.scriptCount}),i.status(200).json({status:"completed",instanceCount:r.instanceCount,scriptCount:r.scriptCount,syncRoot:this.ctx.config.getPlaceRoot(e)})}catch(f){throw l&&l.endFullSyncReplacement(),f}finally{this.endInitRequest(r)}}setPreserveLocalFiles(e,n){this.preserveLocalFilesMap.set(e,n)}getAndClearPreserveLocalFiles(e){let n=this.preserveLocalFilesMap.get(e)||[];return this.preserveLocalFilesMap.delete(e),n}clearPreserveLocalFiles(e){this.preserveLocalFilesMap.delete(e)}clearPendingServiceTrees(e){this.pendingServiceTrees.delete(e)}startTTLTimerForPlace(e,n){e.incompleteSyncTimer&&(clearTimeout(e.incompleteSyncTimer),e.incompleteSyncTimer=null);let i=setTimeout(async()=>{if(y.warn("Incomplete sync TTL expired, cleaning up",{placeId:e.placeId,syncId:n}),e.incompleteSyncTimer=null,e.activeFullSyncSessionId===n&&e.syncInitRequestsInFlight>0){y.warn("Incomplete sync TTL expired while sync init request is in flight, extending cleanup",{placeId:e.placeId,syncId:n,syncInitRequestsInFlight:e.syncInitRequestsInFlight}),this.startTTLTimerForPlace(e,n);return}let r=this.ctx.config.getPlaceRoot(e.placeId),a=Me.join(r,`explorer_tmp_${n}`);try{await jn.rm(a,{recursive:!0,force:!0})}catch(o){y.error("Failed to clean up expired temp dir",o instanceof Error?o:new Error(String(o)))}e.activeFullSyncSessionId===n&&(e.activeFullSyncSessionId=null,e.activeClientId=null,e.state="idle",e.tmpIndex=null,e.syncInitRequestsInFlight=0,this.pendingServiceTrees.delete(n),e.collisionDirMap=null,e.activeSyncIdentityScope=null,e.tmpWriter&&(e.tmpWriter.stopChangeLogFlusher(),e.tmpWriter=null),this.ctx.activeFullSyncPlaceId===e.placeId&&(this.ctx.activeFullSyncPlaceId=null),this.ctx.clearRuntimePlaceIfMatch(e.placeId))},Z8);i&&typeof i=="object"&&"unref"in i&&i.unref(),e.incompleteSyncTimer=i}getOrCreatePendingServiceTree(e,n){let i=this.pendingServiceTrees.get(e);i||(i=new Map,this.pendingServiceTrees.set(e,i));let r=i.get(n.serviceName);if(r)return r;let a={serviceName:n.tree?.name??n.serviceName,serviceClassName:n.tree?.className??n.serviceClassName,zeroBasedChunkIndex:n.chunkIndex===0,instances:[]};return i.set(n.serviceName,a),a}isLastChunk(e,n,i){return i<=1?!0:e.zeroBasedChunkIndex?n>=i-1:n>=i}getPreferredResolvedName(e,n,i){let r=typeof i.sessionDebugId=="string"?i.sessionDebugId:"";if(!n||r==="")return;let a=e.index.getSessionDebugMapping(n,r);if(!a)return;let o=St(i.path),s=lt(i.path)||i.name;if(!(a.parentPath!==o||a.originalName!==s))return a.resolvedName}recordSessionDebugMapping(e,n,i,r){let a=typeof i.sessionDebugId=="string"?i.sessionDebugId:"";!n||a===""||!e.tmpIndex||e.tmpIndex.setSessionDebugMapping({scope:n,sessionDebugId:a,instancePath:i.path,parentPath:St(i.path),originalName:lt(i.path)||i.name,siblingIndex:Math.max(1,i.siblingIndex??1),resolvedName:r,className:i.className,updatedAt:new Date().toISOString()})}buildServiceTree(e,n){let i={name:n.serviceName,className:n.serviceClassName,childCount:0,children:[],syncedAt:new Date().toISOString()};for(let r of n.instances){let a=this.resolveEffectiveSegments(e,r.effectivePath),o=Kt(r.originalPath);this.upsertTreeNode(i,a,o,r.className)}return this.recomputeTreeChildCounts(i),i.syncedAt=new Date().toISOString(),i}resolveEffectiveSegments(e,n){return e.tmpIndex?Kt(n).map(i=>e.tmpIndex.sanitizeName(i)):Kt(n)}rewritePendingEffectivePaths(e,n,i,r){let a=Me.relative(n,i).split(Me.sep).filter(l=>l.length>0),o=Me.relative(n,r).split(Me.sep).filter(l=>l.length>0);if(a.length===0||o.length===0)return;let s=gt(["game",...a]),c=gt(["game",...o]);for(let l of e.instances){if(l.effectivePath===s){l.effectivePath=c;continue}(l.effectivePath.startsWith(`${s}.`)||l.effectivePath.startsWith(`${s}[`))&&(l.effectivePath=`${c}${l.effectivePath.slice(s.length)}`)}}upsertTreeNode(e,n,i,r){if(n.length<=1)return;let a=e.children;for(let o=1;o<n.length;o++){let s=n[o],c=i[o],l=o===n.length-1,u=a.find(d=>d.name===s);u?l&&(u.className=r,c!==void 0&&c!==s&&(u.originalName=c)):(u={name:s,className:l?r:"Folder",childCount:0,children:[]},c!==void 0&&c!==s&&(u.originalName=c),a.push(u)),u.children||(u.children=[]),a=u.children}}recomputeTreeChildCounts(e){let n=i=>{let r=i.children??[];i.children=r;for(let a of r)n(a);i.childCount=r.length};for(let i of e.children)n(i);e.childCount=e.children.length}clearTTLTimerForPlace(e,n){e.incompleteSyncTimer&&e.activeFullSyncSessionId===n&&(clearTimeout(e.incompleteSyncTimer),e.incompleteSyncTimer=null)}beginInitRequest(e){e.syncInitRequestsInFlight++}endInitRequest(e){e.syncInitRequestsInFlight=Math.max(0,e.syncInitRequestsInFlight-1)}async cleanupStaleTempDirs(){let e=this.ctx.config.getSyncRoot();try{let n=await jn.readdir(e,{withFileTypes:!0});for(let i of n)if(i.isDirectory()){if(i.name.startsWith("explorer_tmp_")){let r=Me.join(e,i.name);y.warn("Removing stale temp directory from crashed sync",{dir:i.name});try{await jn.rm(r,{recursive:!0,force:!0})}catch(a){y.error(`Failed to remove stale temp dir: ${i.name}`,a instanceof Error?a:new Error(String(a)))}}if(i.name.startsWith("place_")){let r=Me.join(e,i.name);try{let a=await jn.readdir(r,{withFileTypes:!0});for(let o of a)if(o.isDirectory()&&o.name.startsWith("explorer_tmp_")){let s=Me.join(r,o.name);y.warn("Removing stale temp directory from crashed sync",{dir:`${i.name}/${o.name}`});try{await jn.rm(s,{recursive:!0,force:!0})}catch(c){y.error(`Failed to remove stale temp dir: ${i.name}/${o.name}`,c instanceof Error?c:new Error(String(c)))}}}catch{continue}}}}catch(n){if(n.code==="ENOENT")return;y.warn("Failed to scan for stale temp dirs",{error:n instanceof Error?n.message:String(n)})}}};import kr from"path";import{promises as xx}from"fs";Sr();ce();var _x=class{constructor(e){this.ctx=e}async handleReversePending(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({pending:0,hasConflicts:!1,lastDetected:null});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}let a={pending:r.fileWatcher?.getPendingCount()??0,hasConflicts:!1,lastDetected:r.fileWatcher?.getLastDetected()??null,forwardRestoreNeeded:r.forwardRestoreQueue.length};this.ctx.touchRuntimePlace(i),n.status(200).json(a)}async handleReverseSyncChanges(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({changes:[],count:0});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}if(r.state!=="syncing"){n.status(400).json({error:"Not syncing",message:"Reverse sync is only available when sync is active"});return}let a=r.fileWatcher?.drainPendingChanges()??[],o=a.length>0?await r.reader.buildChangesFromPending(a):[];this.ctx.touchRuntimePlace(i),n.status(200).json({changes:o,count:o.length})}async handleReverseSyncResult(e,n){let i=e.body,r=i.placeId??this.ctx.getDefaultRuntimePlaceId();if(r==null){n.status(400).json({error:"Validation error",message:"placeId is required (in body or via active sync session)"});return}let a=i.appliedFiles??i.appliedPaths;if(!a||!Array.isArray(a)){n.status(400).json({error:"Validation error",message:"appliedFiles (or appliedPaths) must be an array of relative file paths"});return}let o=this.ctx.places.get(r);if(!o){n.status(404).json({error:"Place not found",message:`No sync context for place ${r}`});return}this.ctx.touchRuntimePlace(r);let s=this.ctx.config.getPlaceRoot(r),c=0,l=[];for(let u of a){let d=kr.resolve(s,u);if(!gx(s,d)){l.push({path:u,error:"Path is outside the place root"});continue}try{let p=await xx.readFile(d,"utf-8"),f=o.index.computeHash(p);o.index.updateHashByValue(d,f),o.index.updateFileHashByValue(d,f),c++}catch(p){let f=p.code;if(f==="ENOENT"){o.index.removeHash(d),o.index.removeHashesUnder(d);let m=this.resolveInstancePathForAppliedPath(o.index,d);if(m){let g=lt(m),h=St(m);h&&g&&await o.writer.removeFromTree(h,g)}c++}else f==="EISDIR"?c++:l.push({path:u,error:p instanceof Error?p.message:String(p)})}}c>0&&await o.index.saveToDisk(),c>0&&o.writer.appendHistory({timestamp:new Date().toISOString(),type:"reverseApply",direction:"reverse",source:"local",path:`place_${r}`,details:`applied:${c} failed:${l.length}`}),n.status(200).json({updated:c,failed:l.length,errors:l})}async handleResolveConflict(e,n){let i=e.body;if(!i.fsPath||!i.resolution){n.status(400).json({error:"Validation error",message:"fsPath and resolution are required"});return}let{fsPath:r,resolution:a}=i,o=this.ctx.config.getSyncRoot();if(!gx(o,kr.resolve(o,r))){n.status(403).json({error:"Forbidden",message:"Path is outside the sync root"});return}if(a==="skip"){n.status(200).json({status:"skipped",fsPath:r});return}let s;if(i.placeId&&(s=this.ctx.places.get(i.placeId)),!s){let p=r.match(/^place_(\d+)(?:_[^/]+)?\//);if(p){let f=parseInt(p[1],10);s=this.ctx.places.get(f)}else s=Array.from(this.ctx.places.values())[0]}if(!s){n.status(404).json({error:"No active place context",message:"No sync session is active. Start a sync first."});return}let c=this.ctx.config.getPlaceRoot(s.placeId),l=kr.resolve(c,r);if(!gx(c,l)){n.status(403).json({error:"Forbidden",message:"Path is outside the place root"});return}let u=s.index,d=s.reader;if(a==="apply-studio"){if(typeof i.studioContent!="string"){n.status(400).json({error:"Validation error",message:"studioContent is required for apply-studio resolution"});return}await xx.mkdir(kr.dirname(l),{recursive:!0});let p=i.studioContent,f=u.computeHash(p);s.fileWatcher?.suppressPath(l,f),await xx.writeFile(l,p,"utf-8"),u.updateHashByValue(l,f),u.updateFileHashByValue(l,f),await u.saveToDisk(),n.status(200).json({status:"resolved",resolution:"apply-studio",fsPath:r});return}if(a==="apply-file"){let p=await xx.readFile(l,"utf-8"),f=u.computeHash(p);u.resolveFile(l,"apply-file",f),await u.saveToDisk();let m=d.getFileType(l),g=d.resolveInstancePathFromFile(l);n.status(200).json({status:"resolved",resolution:"apply-file",fsPath:r,instancePath:g,fileType:m,content:p});return}n.status(400).json({error:"Invalid resolution",message:`Unknown resolution: ${a}`})}async handleReverseRescan(e,n){let i=this.ctx.resolveQueryPlaceId(e);if(i==null){n.status(200).json({added:0});return}let r=this.ctx.places.get(i);if(!r){n.status(404).json({error:"Place not found",message:`No sync context for place ${i}`});return}if(!r.fileWatcher){n.status(200).json({added:0});return}let a=await r.fileWatcher.rescan();this.ctx.touchRuntimePlace(i),y.info("Reverse rescan completed",{placeId:i,added:a}),n.status(200).json({added:a})}resolveInstancePathForAppliedPath(e,n){let i=e.resolveInstancePathFromFsPath(n);if(i)return i;let r=e.getExplorerRoot(),a=kr.relative(r,n);if(a.startsWith("..")||a===""||kr.isAbsolute(a))return null;let o=a.split(kr.sep).filter(f=>f.length>0);if(o.length<2)return null;let s=kr.basename(n),c=kr.dirname(n),l=e.getOriginalInstance(c,s);if(l)return l.instancePath;let u=s.toLowerCase();if(jb.some(f=>u.endsWith(f))||u==="_tree.json")return null;let d=["game"],p=r;for(let f of o){p=kr.join(p,f);let m=kr.dirname(p);d.push(e.getOriginalNameForDir(m,f))}return gt(d)}};Sr();Lb();ce();var Hfe=5;function J8(t){if(!t||typeof t!="object")return;let e=t;if(Array.isArray(e.instances))for(let n of e.instances)Array.isArray(n.properties)&&n.properties.length===0&&(n.properties={}),Array.isArray(n.attributes)&&n.attributes.length===0&&(n.attributes={});if(Array.isArray(e.changes))for(let n of e.changes)Array.isArray(n.properties)&&n.properties.length===0&&(n.properties={}),Array.isArray(n.attributes)&&n.attributes.length===0&&(n.attributes={})}function Zfe(t){return t.type==="instanceAdded"||t.type==="instanceRemoved"||t.type==="instanceRenamed"||t.type==="instanceMoved"||t.type==="scriptSourceChanged"}var Kr=class{config;places;apiHandler;changeProcessor;initHandler;reverseHandler;reverseDetectorFactory;activeFullSyncPlaceId=null;activeRuntimeSyncPlaceId=null;currentConnectedPlaceId=null;currentConnectedPlaceName=null;constructor(e,n={}){this.config=new $b(e,n),this.reverseDetectorFactory=n.reverseDetectorFactory??(i=>new px(i.explorerRoot,i.syncIndex,{placeId:i.placeId})),this.apiHandler=new vx(this),this.changeProcessor=new hx(this),this.initHandler=new bx(this),this.reverseHandler=new _x(this),this.places=new ux({max:Hfe,dispose:(i,r)=>{y.info("Disposing place context (LRU eviction)",{placeId:r}),this.activeFullSyncPlaceId===r&&(this.activeFullSyncPlaceId=null),i.fileWatcher&&(y.info("Disposing place context: stopping reverse detector",{placeId:r,reason:"lru-dispose",mode:ut}),i.fileWatcher.stop("lru-dispose").catch(a=>{y.error("Error stopping reverse detector during dispose",a)}),i.fileWatcher=null),i.writer.stopChangeLogFlusher().catch(a=>{y.error("LRU dispose \uC911 changelog flush \uC2E4\uD328",a)}),i.incompleteSyncTimer&&(clearTimeout(i.incompleteSyncTimer),i.incompleteSyncTimer=null),i.index.clearAllMaps(),i.index.saveToDisk().catch(a=>{y.error("Error saving index during dispose",a)}),i.activeFullSyncSessionId&&this.initHandler.clearPendingServiceTrees(i.activeFullSyncSessionId),i.tmpWriter&&(i.tmpWriter.stopChangeLogFlusher(),i.tmpWriter=null),i.tmpIndex=null,i.collisionDirMap=null,i.activeSyncIdentityScope=null,i.syncInitRequestsInFlight=0}})}getSyncRoot(){return this.config.getSyncRoot()}async getOrCreatePlaceContext(e,n){let i=this.places.get(e);if(i&&n){let r=this.config.getPlaceRoot(e),a=await this.config.resolvePlaceRoot(e,n);a!==r&&(y.info("Place root migrated, recreating context",{placeId:e,from:r,to:a}),this.places.delete(e),i=void 0)}if(!i){let r=await this.config.resolvePlaceRoot(e,n),a=TE.join(r,"explorer");await Pl.mkdir(r,{recursive:!0}),await Pl.mkdir(a,{recursive:!0});let o=new Fa(r,a);await o.loadFromDisk();let s=new Cl(this.config,o,e),c=new dx(this.config,o,r);s.startChangeLogFlusher(),i={placeId:e,placeName:"",index:o,writer:s,reader:c,fileWatcher:null,state:"idle",activeClientId:null,activeFullSyncSessionId:null,instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,tmpIndex:null,tmpWriter:null,incompleteSyncTimer:null,syncInitRequestsInFlight:0,changesSinceLastSave:0,directions:{...Wo},applyModes:{...Go},autoApplyDeletes:!1,forwardRestoreQueue:[],syncProgress:null,collisionDirMap:null,activeSyncIdentityScope:null},this.places.set(e,i),y.info("Created new place context",{placeId:e,placeRoot:r})}return i}async handleSyncInit(e,n){try{J8(e.body);let i=W8(e.body);if(!i.success){n.status(400).json({error:"Validation error",message:i.error});return}let r=i.data,a=r.phase==="start"?r.placeId??null:r.phase==="chunk"||r.phase==="complete"?this.activeFullSyncPlaceId:null;if(a==null){n.status(400).json({error:"Missing placeId",message:"placeId is required in start phase or must be set by previous start"});return}switch(r.phase){case"start":this.setCurrentConnectedPlace(a,r.placeName),await this.initHandler.handleInitStart(a,r,n);break;case"chunk":await this.initHandler.handleInitChunk(a,r,n);break;case"complete":await this.initHandler.handleInitComplete(a,r,n);break}}catch(i){this.sendError(n,i,"handleSyncInit")}}async handleSyncUpdate(e,n){try{J8(e.body);let i=G8(e.body);if(!i.success){n.status(400).json({error:"Validation error",message:i.error});return}let r=i.data,a=r.placeId??this.getDefaultRuntimePlaceId();if(a==null){n.status(400).json({error:"Missing placeId",message:"placeId is required in body or must have an active sync session"});return}let o=await this.getOrCreatePlaceContext(a);if(this.setCurrentConnectedPlace(a,o.placeName||this.currentConnectedPlaceName),o.activeFullSyncSessionId!==null||o.state==="initializing"){n.status(409).json({error:"Conflict",message:`Full sync in progress for place ${a}`});return}o.activeClientId=r.clientId,this.touchRuntimePlace(a);let s=H8(o,r.changes);y.info("Sync update received",{placeId:a,clientId:r.clientId,changeCount:s.length,receivedCount:r.changes.length,types:s.map(m=>m.type)});let c=[],l=[],u=0,d=!1,p=new Map;for(let m of s)try{let g=await this.changeProcessor.processChangeForPlace(o,m,p);g?l.push(g):(u++,Zfe(m)&&(d=!0))}catch(g){let h="path"in m?m.path:"oldPath"in m?m.oldPath:"unknown";c.push({path:h,error:g instanceof Error?g.message:String(g)})}for(let m of p.values())try{await fx(o,m)}catch(g){c.push({path:m.instancePath,error:g instanceof Error?g.message:String(g)})}if(d)try{let m=this.config.getSyncRoot(),g=this.config.getPlaceRoot(a);await zb(m,g),await ll(m)}catch(m){y.warn("Failed to refresh sourcemaps after incremental sync update",{placeId:a,error:m instanceof Error?m.message:String(m)})}o.changesSinceLastSave+=u,o.changesSinceLastSave>=V8&&(await o.index.saveToDisk(),o.changesSinceLastSave=0),o.lastIncrementalSync=new Date().toISOString();let f={processed:u,failed:c.length,errors:c,syncedAt:o.lastIncrementalSync};l.length>0&&(f.conflicts=l),n.status(200).json(f)}catch(i){this.sendError(n,i,"handleSyncUpdate")}}getDefaultRuntimePlaceId(){return this.currentConnectedPlaceId}getDefaultRuntimePlaceName(){if(this.currentConnectedPlaceName)return this.currentConnectedPlaceName;if(this.currentConnectedPlaceId!==null&&this.currentConnectedPlaceId!==void 0){let e=this.places.get(this.currentConnectedPlaceId);if(e?.placeName)return e.placeName}return null}setCurrentConnectedPlace(e,n){if(this.currentConnectedPlaceId=e,e==null){this.currentConnectedPlaceName=null;return}if(typeof n=="string"&&n.length>0){this.currentConnectedPlaceName=n;let r=this.places.get(e);r&&(r.placeName=n);return}let i=this.places.get(e);i?.placeName&&(this.currentConnectedPlaceName=i.placeName)}clearCurrentConnectedPlaceIfMatch(e){this.currentConnectedPlaceId===e&&(this.currentConnectedPlaceId=null,this.currentConnectedPlaceName=null)}touchRuntimePlace(e){this.activeRuntimeSyncPlaceId=e}clearRuntimePlaceIfMatch(e){this.activeRuntimeSyncPlaceId===e&&(this.activeRuntimeSyncPlaceId=null)}resolveQueryPlaceId(e,n="runtime"){let i=e.query.placeId;if(i){let r=parseInt(i,10);if(!isNaN(r))return r}return n==="full"?this.activeFullSyncPlaceId:this.getDefaultRuntimePlaceId()}async handleSyncStatus(e,n){try{let i=u=>({state:"idle",instanceCount:0,scriptCount:0,lastFullSync:null,lastIncrementalSync:null,syncRoot:u,activeClientId:null,reverseSyncAvailable:!1,modifiedFileCount:0,autoApplyDeletes:!1,reverseDetectorActive:!1,reverseDetectorMode:ut,fileWatcherActive:!1}),r=this.resolveQueryPlaceId(e);if(r==null){let u=i(this.config.getSyncRoot());n.status(200).json(u);return}let a=this.places.get(r);if(!a){let u=i(this.config.getPlaceRoot(r));n.status(200).json(u);return}let o=a.fileWatcher?.getPendingCount()??0,s=a.fileWatcher?.isActivelyScanning()??!1,c=a.fileWatcher!==null;this.touchRuntimePlace(r);let l={state:a.state,instanceCount:a.instanceCount,scriptCount:a.scriptCount,lastFullSync:a.lastFullSync,lastIncrementalSync:a.lastIncrementalSync,syncRoot:this.config.getPlaceRoot(r),activeClientId:a.activeClientId,reverseSyncAvailable:o>0,modifiedFileCount:o,applyModes:a.applyModes,autoApplyDeletes:a.autoApplyDeletes,directions:a.directions,reverseDetectorActive:s,reverseDetectorMode:ut,fileWatcherActive:c,forwardOnlyClasses:[...cl]};n.status(200).json(l)}catch(i){this.sendError(n,i,"handleSyncStatus")}}async handleSyncStop(e,n){try{let i=e.body,r=i.placeId??this.getDefaultRuntimePlaceId(),a=lf(i);if(y.info("handleSyncStop requested",{placeId:r,clientId:i.clientId??null,identityScope:a,reason:i.reason??"requested"}),r==null){n.status(200).json({status:"idle",state:"idle",placeId:null,message:"No active sync place"});return}let o=this.places.get(r);if(!o){y.info("handleSyncStop no place context",{placeId:r,clientId:i.clientId??null}),n.status(200).json({status:"idle",state:"idle",placeId:r,message:`No sync context for place ${r}`});return}let s=!!(i.clientId&&o.activeClientId&&i.clientId!==o.activeClientId),c=o.activeFullSyncSessionId!==null||o.state==="syncing"||o.state==="initializing",l=!!(a&&o.activeSyncIdentityScope&&a===o.activeSyncIdentityScope);if(s&&c&&!l){y.warn("handleSyncStop rejected due to active client mismatch",{placeId:r,requestedClientId:i.clientId,activeClientId:o.activeClientId,requestedIdentityScope:a,activeIdentityScope:o.activeSyncIdentityScope,state:o.state,activeFullSyncSessionId:o.activeFullSyncSessionId}),n.status(409).json({error:"Conflict",message:`This sync session belongs to client ${o.activeClientId}`});return}s&&l&&y.info("handleSyncStop accepted stale client cleanup by identity scope",{placeId:r,requestedClientId:i.clientId,activeClientId:o.activeClientId,identityScope:a,state:o.state});let u=o.activeFullSyncSessionId,d=o.state,p=o.fileWatcher!==null;if(u&&(this.initHandler.clearPreserveLocalFiles(u),this.initHandler.clearPendingServiceTrees(u)),o.fileWatcher&&(y.info("handleSyncStop suspending reverse detector",{placeId:r,state:o.state,activeClientId:o.activeClientId,mode:ut}),o.fileWatcher.beginFullSyncReplacement()),o.incompleteSyncTimer&&(clearTimeout(o.incompleteSyncTimer),o.incompleteSyncTimer=null),u){let f=this.config.getPlaceRoot(r),m=TE.join(f,`explorer_tmp_${u}`);await Pl.rm(m,{recursive:!0,force:!0}).catch(()=>{})}o.tmpWriter&&(o.tmpWriter.stopChangeLogFlusher(),o.tmpWriter=null),o.tmpIndex=null,o.collisionDirMap=null,o.activeSyncIdentityScope=null,o.syncInitRequestsInFlight=0,o.activeFullSyncSessionId=null,o.syncProgress=null,o.state="idle",o.activeClientId=null,o.instanceCount=0,o.scriptCount=0,o.forwardRestoreQueue=[],this.activeFullSyncPlaceId===r&&(this.activeFullSyncPlaceId=null),this.clearRuntimePlaceIfMatch(r),y.info("handleSyncStop responding idle",{placeId:r,previousState:d,activeFullSyncSessionId:u,hadWatcher:p}),y.info("Sync stopped",{placeId:r,reason:i.reason??"requested"}),n.status(200).json({status:"stopped",state:"idle",placeId:r})}catch(i){this.sendError(n,i,"handleSyncStop")}}async initialize(){try{await this.config.loadFromMeta(),await this.initHandler.cleanupStaleTempDirs(),y.info("SyncController initialized")}catch(e){y.error("SyncController initialization failed",e instanceof Error?e:new Error(String(e)))}}async shutdown(){try{y.info("SyncController shutdown: clearing place contexts",{placeCount:this.places.size}),this.places.clear(),y.info("SyncController shut down")}catch(e){y.error("SyncController shutdown error",e instanceof Error?e:new Error(String(e)))}}async atomicWriteFile(e,n){let i=e+".tmp."+Bfe().slice(0,8);try{await Pl.writeFile(i,n,"utf-8"),await Pl.rename(i,e)}catch(r){throw await Pl.unlink(i).catch(()=>{}),r}}async handlePreCheck(e,n){try{await this.apiHandler.handlePreCheck(e,n)}catch(i){this.sendError(n,i,"handlePreCheck")}}async handleSyncDirections(e,n){try{await this.apiHandler.handleSyncDirections(e,n)}catch(i){this.sendError(n,i,"handleSyncDirections")}}async handleForwardRestoreList(e,n){try{await this.apiHandler.handleForwardRestoreList(e,n)}catch(i){this.sendError(n,i,"handleForwardRestoreList")}}async handleReversePending(e,n){try{await this.reverseHandler.handleReversePending(e,n)}catch(i){this.sendError(n,i,"handleReversePending")}}async handleReverseSyncChanges(e,n){try{await this.reverseHandler.handleReverseSyncChanges(e,n)}catch(i){this.sendError(n,i,"handleReverseSyncChanges")}}async handleReverseSyncResult(e,n){try{await this.reverseHandler.handleReverseSyncResult(e,n)}catch(i){this.sendError(n,i,"handleReverseSyncResult")}}async handleResolveConflict(e,n){try{await this.reverseHandler.handleResolveConflict(e,n)}catch(i){this.sendError(n,i,"handleResolveConflict")}}async handleReverseRescan(e,n){try{await this.reverseHandler.handleReverseRescan(e,n)}catch(i){this.sendError(n,i,"handleReverseRescan")}}async handleSyncHistory(e,n){try{await this.apiHandler.handleSyncHistory(e,n)}catch(i){this.sendError(n,i,"handleSyncHistory")}}async startFileWatcherForPlace(e){if(e.state!=="syncing"){y.debug("Skipping reverse detector start - place not syncing",{placeId:e.placeId,state:e.state});return}if(e.fileWatcher){if(e.fileWatcher.isActivelyScanning()){y.info("startFileWatcherForPlace: reusing active reverse detector",{placeId:e.placeId,mode:ut});return}y.info("startFileWatcherForPlace: resuming paused reverse detector",{placeId:e.placeId,mode:ut}),e.fileWatcher.endFullSyncReplacement();return}let n=this.createReverseChangeDetector(e);this.configureReverseChangeDetector(e,n),e.fileWatcher=n,n.start().then(()=>{e.fileWatcher===n&&y.info("Reverse detector started for reverse sync",{placeId:e.placeId,mode:ut})}).catch(i=>{y.warn("Failed to start reverse detector",{placeId:e.placeId,mode:ut,error:i instanceof Error?i.message:String(i)}),e.fileWatcher===n&&(e.fileWatcher=null)})}createReverseChangeDetector(e){return this.reverseDetectorFactory({explorerRoot:TE.join(this.config.getPlaceRoot(e.placeId),"explorer"),syncIndex:e.index,placeId:e.placeId})}configureReverseChangeDetector(e,n){e.writer.setOnWriteCallback(i=>{n.suppressPath(i)}),n.setDirectionChecker(i=>{let r=I6(i);return e.directions[r]}),n.setOnForwardViolation(i=>{e.forwardRestoreQueue.includes(i)||(e.forwardRestoreQueue.push(i),y.info("Forward violation queued for restore",{placeId:e.placeId,relativePath:i,queueSize:e.forwardRestoreQueue.length}))})}getStatusSummary(){return this.apiHandler.getStatusSummary()}getDirectionForCategory(e){return this.apiHandler.getDirectionForCategory(e)}getStatusDirect(e){return this.apiHandler.getStatusDirect(e)}async getHistoryDirect(e,n){return this.apiHandler.getHistoryDirect(e,n)}getDirectionsDirect(e){return this.apiHandler.getDirectionsDirect(e)}getProgressDirect(e){return this.apiHandler.getProgressDirect(e)}async readSyncedFile(e,n){return this.apiHandler.readSyncedFile(e,n)}async writeSyncedFile(e,n,i){await this.apiHandler.writeSyncedFile(e,n,i)}async executeViaDisk(e,n){return this.apiHandler.executeViaDisk(e,n)}sendError(e,n,i){let r=n instanceof Error?n.message:String(n);if(r.includes("Path traversal detected")){e.status(403).json({error:"Forbidden",message:r});return}let a=n.code;if(a==="ENOSPC"||a==="EPERM"||a==="EACCES"){y.warn(`SyncController.${i} disk error`,{code:a,message:r}),e.status(500).json({error:"Disk error",message:r,code:a,operation:i});return}y.error(`SyncController.${i} failed`,n instanceof Error?n:new Error(r)),e.status(500).json({error:"Internal error",message:`${i}: ${r}`})}};import{randomUUID as Vfe}from"crypto";function Y8(t,e){let n=Vfe(),i=n.replace(/-/g,"").substring(0,8).toUpperCase(),r=`${i.substring(0,4)}-${i.substring(4,8)}`;return{config:t,app:e,instanceId:n,sessionId:r,startTime:Date.now(),baseUrl:`http://${t.httpHost}:${t.httpPort}`,commandQueue:new Map,pendingCommands:new Map,globalPendingCommands:[],totalCommandsProcessed:0,pluginClients:new Map,pluginCommandSessionsByClientId:new Map,pluginCommandClientIdsByProcessToken:new Map,mcpInstances:new Map,cachedSelectionMap:new Map,studioRoutingMode:"recentPriority",pinnedTargetClientId:null,isClientMode:!1,clientModeHealthTimer:null,clientModeConsecutiveHealthFailures:0,clientModeUpstreamReachable:!0,clientModeUpstreamContextCaptureEnabled:!0,clientModeLastHealthSuccessAt:null,clientModeLastHealthFailureAt:null,clientModeLastHealthError:null,shuttingDown:!1,onUpstreamPermanentlyDown:null,clientModeIdleTimeoutMs:t.clientModeIdleTimeoutMs??36e5,clientModeIdleWatchdogTimer:null,shutdownFn:null,historyManager:null,analyticsManager:null,executionContextManager:null,licenseState:null,syncController:null,internalCommandExecutor:null,dashboardFolderPicker:null,assetLibraryOpenCloudServiceFactory:null,activeSyncOwnerInstanceId:null,activeProjectRoot:null,pendingDashboardSyncRootPin:null,playtestControlCommand:null,dashboardSyncRootSwitchInFlight:!1,uiStudioRecorders:new Map,aiClientName:"",pluginVersion:"",syncedSessionToken:null,serverLastCommandAt:null}}var X8=Pt(Ta(),1);ce();function Q8(t){let e=X8.default.json({limit:"5mb"});t.app.use((n,i,r)=>{if(n.path.startsWith("/sync/")){r();return}e(n,i,r)}),t.app.use((n,i,r)=>{i.setHeader("Access-Control-Allow-Origin","http://localhost:3002"),i.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),i.setHeader("Access-Control-Allow-Headers","Content-Type"),r()}),t.app.use((n,i,r)=>{y.debug(`${n.method} ${n.path}`,{ip:n.ip}),r()})}xa();import{randomUUID as Yx}from"crypto";xa();ce();function Wfe(){let t=process.env.WEPPY_ROBLOX_MCP_VERSION?.trim();return t||null}var Xe=Wfe()??"2.10.2";wi();tr();ff();Da();fl();xa();Da();var aq="studio-",Kfe=/^studio-[1-9]\d*$/;function Ix(t){return Kfe.test(t)}function oq(t,e){let n=new Set;for(let i of t)e!==void 0&&i.clientId===e||i.targetAlias&&Ix(i.targetAlias)&&n.add(i.targetAlias);return n}function Jfe(t,e){let n=oq(t,e),i=1;for(;n.has(`${aq}${i}`);)i+=1;return`${aq}${i}`}function kx(t,e){let n=oq(t,e.clientId);return e.targetAlias&&Ix(e.targetAlias)&&!n.has(e.targetAlias)||(e.targetAlias=Jfe(t,e.clientId)),e.targetAlias}fl();function Px(t){for(let e of t)kx(t,e)}function Rx(t){let e={clientId:t.clientId,targetAlias:t.targetAlias??t.clientId.slice(0,8),lastSeen:t.lastSeen,connectedAt:t.connectedAt,transport:"websocket",connectionState:t.commandSessionState??Ze.CONNECTED};return t.placeId!==void 0&&(e.placeId=t.placeId),t.placeName!==void 0&&(e.placeName=t.placeName),t.pluginVersion!==void 0&&(e.pluginVersion=t.pluginVersion),t.studioVersion!==void 0&&(e.studioVersion=t.studioVersion),t.lastRoutedAt!==void 0&&(e.lastRoutedAt=t.lastRoutedAt),t.processToken!==void 0&&(e.processToken=t.processToken),t.inFlightRequestId!==void 0&&(e.inFlightRequestId=t.inFlightRequestId),t.studioState!==void 0&&(e.studioState=t.studioState),t.studioStateSource!==void 0&&(e.studioStateSource=t.studioStateSource),t.studioStateUpdatedAt!==void 0&&(e.studioStateUpdatedAt=t.studioStateUpdatedAt),t.playtestMode!==void 0&&(e.playtestMode=t.playtestMode),e}function ME(t){let e=Cn(t);return Px(e),ef(e.map(Rx),null)}function Ex(t){let e=new Set;t.aiClientName&&e.add(t.aiClientName);for(let n of t.mcpInstances.values())n.aiClientName&&e.add(n.aiClientName);return Array.from(e)}function sq(t){let n=Date.now();for(let[i,r]of t.mcpInstances)r.lastSeen&&n-r.lastSeen>15e3&&(t.mcpInstances.delete(i),r.sessionId&&t.executionContextManager?.endSession(r.sessionId),y.debug("Removed stale MCP instance",{instanceId:i,lastSeen:r.lastSeen}))}function cq(t,e,n){let i=e.query.clientId;if(i&&t.pluginClients.has(i)){let r=t.pluginClients.get(i);r.lastSeen=Date.now()}try{let r=e.body;if(!r||!Array.isArray(r.selection)||typeof r.count!="number"){y.warn("Invalid selection update request",{body:r}),n.status(400).json({error:"Invalid request body"});return}let a=i||"unknown",o=Date.now();t.cachedSelectionMap.set(a,{selection:r.selection,count:r.count,timestamp:o,clientId:a}),y.debug("Selection cache updated",{count:r.count,clientId:a,timestamp:o}),n.json({status:"ok",timestamp:o})}catch(r){y.error("Error handling selection update",r),n.status(500).json({error:"Internal server error"})}}function lq(t,e,n){let i=parseInt(e.query.maxAge)||3e4,r=mf(t,i);r?n.json({cached:!0,...r}):n.json({cached:!1,message:"No cached selection available"})}function mf(t,e=3e4,n){if(t.cachedSelectionMap.size===0)return null;let i;if(n)i=t.cachedSelectionMap.get(n);else for(let a of t.cachedSelectionMap.values())(!i||a.timestamp>i.timestamp)&&(i=a);if(!i)return null;let r=Date.now()-i.timestamp;return e===0||r<=e?i:null}function zE(t,e){let n=t.pluginClients.get(e.clientId),i=Date.now(),r=[...t.pluginClients.values()].filter(c=>c.clientId===e.clientId||c.commandSessionState!==Ze.DISCONNECTED),a=n??{clientId:e.clientId,connectedAt:i,lastSeen:i,commandsProcessed:0,connectionType:"polling"},o=kx(r,a),s={clientId:e.clientId,targetAlias:o,projectName:e.projectName??n?.projectName,placeName:e.placeName??n?.placeName,placeId:e.placeId??n?.placeId,pluginVersion:e.pluginVersion??n?.pluginVersion,studioVersion:e.studioVersion??n?.studioVersion,connectedAt:n?.connectedAt||i,lastSeen:i,commandsProcessed:n?.commandsProcessed||0,connectionType:n?.connectionType||"polling",inFlightRequestId:n?.inFlightRequestId,studioState:n?.studioState,studioStateSource:n?.studioStateSource,studioStateUpdatedAt:n?.studioStateUpdatedAt,playtestMode:n?.playtestMode,...n?.commandSessionState?{commandSessionState:n.commandSessionState}:{},...n?.processToken?{processToken:n.processToken}:{}};return t.pluginClients.set(e.clientId,s),t.syncController&&typeof t.syncController.setCurrentConnectedPlace=="function"&&typeof e.placeId=="number"&&Number.isFinite(e.placeId)&&t.syncController.setCurrentConnectedPlace(e.placeId,e.placeName??null),t.pendingCommands.has(e.clientId)||t.pendingCommands.set(e.clientId,[]),e.pluginVersion&&(t.pluginVersion=e.pluginVersion),typeof s.placeId=="number"&&Number.isFinite(s.placeId)&&ex(t,s.placeId,s.placeName??null),t.analyticsManager&&(e.pluginVersion&&t.analyticsManager.setPluginVersion(e.pluginVersion),t.analyticsManager.trackPluginConnected()),y.info("Plugin client registered",{clientId:e.clientId,targetAlias:o,projectName:e.projectName,placeName:e.placeName,isReconnect:!!n}),{clientInfo:s,sessionId:t.sessionId,mcpVersion:Xe,mcpInstanceCount:t.mcpInstances.size+1,aiClientNames:Ex(t)}}function LE(t,e){let n=t.pluginClients.get(e),i=t.pluginClients.has(e),r=n?.commandSessionState===Ze.CONNECTED;if(t.pluginClients.delete(e),t.pendingCommands.delete(e),i&&pl(t,e),i&&t.syncController&&typeof t.syncController.clearCurrentConnectedPlaceIfMatch=="function"&&typeof n?.placeId=="number"&&Number.isFinite(n.placeId)){let a=[...t.pluginClients.values()].filter(o=>typeof o.placeId=="number"&&Number.isFinite(o.placeId)).sort((o,s)=>s.lastSeen-o.lastSeen)[0];a?t.syncController.setCurrentConnectedPlace?.(a.placeId??null,a.placeName??null):t.syncController.clearCurrentConnectedPlaceIfMatch(n.placeId)}return r&&tf(t,e,"disconnected",n),y.info("Plugin client unregistered",{clientId:e,existed:i}),i}function Tx(t,e,n){try{let i=e.body;if(!i.clientId){n.status(400).json({error:"Missing clientId"});return}let r=zE(t,{clientId:i.clientId,projectName:i.projectName,placeName:i.placeName,placeId:i.placeId,pluginVersion:i.pluginVersion,studioVersion:i.studioVersion});n.json({status:"ok",clientId:i.clientId,targetAlias:r.clientInfo.targetAlias,serverInstanceId:t.instanceId,sessionId:r.sessionId,mcpVersion:r.mcpVersion,connectedAt:r.clientInfo.connectedAt,aiClientNames:r.aiClientNames,serverStartTime:t.startTime,mcpInstanceCount:r.mcpInstanceCount})}catch(i){y.error("Error registering plugin client",i),n.status(500).json({error:"Internal server error"})}}function Ax(t,e,n){let i=e.body?.clientId;if(!i){n.status(400).json({error:"Missing clientId"});return}let r=LE(t,i);n.json({status:"ok",existed:r})}function uq(t,e,n){try{let i=e.body;if(!i.instanceId){n.status(400).json({error:"Missing instanceId"});return}let r=Date.now(),a={instanceId:i.instanceId,...typeof i.sessionId=="string"?{sessionId:i.sessionId}:{},pid:i.pid,connectedAt:r,isServer:!1,lastSeen:r};i.aiClientName&&(a.aiClientName=i.aiClientName),i.cwd&&(a.cwd=i.cwd),"projectRoot"in i&&(a.projectRoot=i.projectRoot),t.mcpInstances.set(i.instanceId,a),rt(t,"mcp_status",{aiClientName:a.aiClientName??"Unknown",instanceId:i.instanceId,status:"registered"}),yl(t,{timestamp:new Date().toISOString(),type:"mcp",status:"registered",instanceId:i.instanceId,message:`MCP registered \u2014 ${a.aiClientName??i.instanceId}`,...a.aiClientName?{aiClientName:a.aiClientName}:{}}),y.info("MCP instance registered (client mode)",{instanceId:i.instanceId,pid:i.pid,cwd:i.cwd}),n.json({status:"ok",instanceId:i.instanceId,serverInstanceId:t.instanceId,sessionId:t.sessionId,mcpVersion:Xe,mcpInstanceCount:t.mcpInstances.size+1})}catch(i){y.error("Error registering MCP instance",i),n.status(500).json({error:"Internal server error"})}}function dq(t,e,n){let i=e.body?.instanceId;if(!i){n.status(400).json({error:"Missing instanceId"});return}let r=t.mcpInstances.get(i),a=!!r;t.mcpInstances.delete(i),r?.sessionId&&t.executionContextManager?.endSession(r.sessionId),a&&(rt(t,"mcp_status",{aiClientName:r?.aiClientName??"Unknown",instanceId:i,status:"unregistered"}),yl(t,{timestamp:new Date().toISOString(),type:"mcp",status:"unregistered",instanceId:i,message:`MCP unregistered \u2014 ${r?.aiClientName??i}`,...r?.aiClientName?{aiClientName:r.aiClientName}:{}})),y.info("MCP instance unregistered",{instanceId:i,existed:a}),n.json({status:"ok",existed:a})}function pq(t,e,n){let{instanceId:i,aiClientName:r}=e.body;if(i&&r){let a=t.mcpInstances.get(i);a&&(a.aiClientName=r)}n.json({status:"ok"})}function fq(t){let e=3e4,n=Date.now(),i=_r({appDataDir:t.config.appDataDir});for(let[a,o]of t.pluginClients)n-o.lastSeen>e&&(t.pluginClients.delete(a),t.pendingCommands.delete(a),pl(t,a));sq(t);let r=Cn(t);return Px(r),{serverInstanceId:t.instanceId,sessionId:t.sessionId,mcpVersion:Xe,uptime:n-t.startTime,serverStartTime:t.startTime,serverExecutable:process.execPath,serverHost:t.config.httpHost,serverPort:t.config.httpPort,serverPid:process.pid,pluginClients:r.map(Rx),studioRoutingMode:t.studioRoutingMode,pinnedTargetClientId:t.pinnedTargetClientId,mcpInstances:[{instanceId:t.instanceId,pid:process.pid,connectedAt:t.startTime,isServer:!0,cwd:process.cwd(),projectRoot:i,lastSeen:n,...t.aiClientName?{aiClientName:t.aiClientName}:{}},...Array.from(t.mcpInstances.values())],mcpInstanceCount:t.mcpInstances.size+1}}function $x(t,e){e.json(fq(t))}function Ox(t,e,n){let i=e.query.instanceId;i&&t.mcpInstances.has(i)&&(t.mcpInstances.get(i).lastSeen=Date.now()),sq(t);let r=Cn(t);Px(r);let s={...{status:"online",connectedClients:r.length,queuedCommands:l8(t),uptime:Date.now()-t.startTime,version:Xe,enableContextCapture:t.executionContextManager?.isEnabled()??t.config.enableContextCapture??!0,isClientMode:t.isClientMode,shuttingDown:t.shuttingDown,pid:process.pid,sessionId:t.sessionId,nodeVersion:process.version,studioRoutingMode:t.studioRoutingMode,pinnedTargetClientId:t.pinnedTargetClientId},instanceId:t.instanceId,mcpInstanceCount:t.mcpInstances.size+1,aiClientNames:Ex(t),pluginVersion:t.pluginVersion||void 0,dashboardSseClients:t.dashboardSseClients?.size??0,websocketClients:r.length,pluginClients:r.map(Rx),...t.isClientMode?{upstream:{reachable:t.clientModeUpstreamReachable,consecutiveFailures:t.clientModeConsecutiveHealthFailures,lastSuccessAt:t.clientModeLastHealthSuccessAt,lastFailureAt:t.clientModeLastHealthFailureAt,lastError:t.clientModeLastHealthError,baseUrl:t.baseUrl}}:{}};n.json(s)}function mq(t,e,n,i){let r=e.ip||e.socket.remoteAddress||"";if(!(r==="127.0.0.1"||r==="::1"||r==="::ffff:127.0.0.1"||r==="localhost")){y.warn("Shutdown request rejected from non-localhost",{ip:r}),n.status(403).json({error:"Forbidden: localhost only"});return}y.info("Shutdown request received, initiating graceful shutdown",{requestedBy:r,uptime:Date.now()-t.startTime}),n.json({status:"shutting_down",message:"Server will shutdown gracefully",pid:process.pid}),setTimeout(async()=>{try{await i(),y.info("Graceful shutdown completed"),process.exit(0)}catch(o){y.error("Error during graceful shutdown",o),process.exit(1)}},100)}async function Dx(t){if(t.isClientMode)try{let e=await fetch(`${t.baseUrl}/connection-info`);if(e.ok)return await e.json()}catch(e){y.warn("Failed to fetch connection info from server",{error:e})}return fq(t)}Da();var dt={bridgeRunTest:"manage_studio_run_test_bridge",placeInfo:"system_info_place_info",clearLogs:"manage_logs_clear",createScript:"manage_scripts_create",getLogs:"manage_logs_get",deleteScript:"manage_scripts_delete",canonical:{playStart:"manage_studio_play_start",playStop:"manage_studio_play_stop",playPause:"manage_studio_play_pause",playResume:"manage_studio_play_resume",playStatus:"manage_studio_play_status",runTest:"manage_studio_run_test"}},Xfe=new Set([dt.canonical.runTest]),Qfe=new Set([dt.canonical.playStop]),q4e=new Set([dt.canonical.playStart,dt.canonical.playStop,dt.canonical.playPause,dt.canonical.playResume,dt.canonical.playStatus]);function Jr(t){return Xfe.has(t)}function gf(t){return Qfe.has(t)}var V4e=dt.canonical.playStop,gq=[5e3,15e3];fl();var eme=new Set(["manage_assets_export_selection_rbxm","manage_assets_export_path_rbxm","manage_assets_review_model","manage_assets_generate_model","manage_assets_import_rbxm","manage_assets_generate_thumbnail"]),on=class t extends Error{code;routing;constructor(e,n,i){super(n),this.name="CommandTargetSelectionError",this.code=e,this.routing=i,Object.setPrototypeOf(this,t.prototype)}};function tme(t={},e){let n={},i=t.clientId,r=t.targetAlias,a=t.placeId;if(i!==void 0){if(typeof i!="string"||i.trim().length===0)throw new on("invalid_target_selector","clientId target selector must be a non-empty string",{selectionMode:"clientId",...typeof i=="string"?{requestedClientId:i.trim()}:{}});n.requestedClientId=i.trim()}if(r!==void 0){if(typeof r!="string"||r.trim().length===0)throw new on("invalid_target_selector","targetAlias target selector must be a non-empty string",{selectionMode:"targetAlias",...typeof r=="string"?{requestedTargetAlias:r.trim()}:{}});n.requestedTargetAlias=r.trim()}if(a!==void 0&&nme(e,t)){if(typeof a!="number"||!Number.isFinite(a))throw new on("invalid_target_selector","placeId target selector must be a finite number",{selectionMode:"placeId"});n.requestedPlaceId=a}return n}function Nx(t,e,n={},i){let r=tme(n,i),a=z6(e,t.studioRoutingMode==="pinned"?t.pinnedTargetClientId:null);if(r.requestedClientId!==void 0)return rme(a,r);if(r.requestedTargetAlias!==void 0)return ime(a,r);if(r.requestedPlaceId!==void 0)return ame(a,r);if(t.studioRoutingMode==="pinned"&&t.pinnedTargetClientId!==null){let s=a.find(c=>c.clientId===t.pinnedTargetClientId);if(s)return{targetClientId:s.clientId,routing:Pr("pinnedTarget",r,s)}}let o=a[0];return o?{targetClientId:o.clientId,routing:Pr("recentPriority",r,o)}:{routing:{selectionMode:"globalQueue"}}}function nme(t,e){return!t||!eme.has(t)?!0:e.scope==="shared"}function rme(t,e){let n=t.find(i=>i.clientId===e.requestedClientId);if(!n)throw new on("target_client_not_found",`Target client not found: ${e.requestedClientId}`,Pr("clientId",e));if(e.requestedTargetAlias!==void 0&&n.targetAlias!==e.requestedTargetAlias)throw new on("target_selector_mismatch",`Target client ${n.clientId} does not match targetAlias ${e.requestedTargetAlias}`,Pr("clientId",e,n));return hq("clientId",e,n),{targetClientId:n.clientId,routing:Pr("clientId",e,n)}}function ime(t,e){let n=t.find(i=>i.targetAlias!==void 0&&Ix(i.targetAlias)&&i.targetAlias===e.requestedTargetAlias);if(!n)throw new on("target_alias_not_found",`Target alias not found: ${e.requestedTargetAlias}`,Pr("targetAlias",e));return hq("targetAlias",e,n),{targetClientId:n.clientId,routing:Pr("targetAlias",e,n)}}function ame(t,e){let n=t.filter(r=>r.placeId===e.requestedPlaceId);if(n.length===0)throw new on("target_place_not_found",`Target place not found: ${e.requestedPlaceId}`,Pr("placeId",e));if(n.length>1)throw new on("target_place_ambiguous",`Target place is ambiguous: ${e.requestedPlaceId}`,Pr("placeId",e));let i=n[0];return{targetClientId:i.clientId,routing:Pr("placeId",e,i)}}function hq(t,e,n){if(e.requestedPlaceId!==void 0&&n.placeId!==e.requestedPlaceId)throw new on("target_selector_mismatch",`Target client ${n.clientId} is not connected to placeId ${e.requestedPlaceId}`,Pr(t,e,n))}function Pr(t,e,n){let i={selectionMode:t};return e.requestedClientId!==void 0&&(i.requestedClientId=e.requestedClientId),e.requestedTargetAlias!==void 0&&(i.requestedTargetAlias=e.requestedTargetAlias),e.requestedPlaceId!==void 0&&(i.requestedPlaceId=e.requestedPlaceId),n!==void 0&&(i.actualClientId=n.clientId,n.targetAlias!==void 0&&(i.actualTargetAlias=n.targetAlias),n.placeId!==void 0&&(i.actualPlaceId=n.placeId),n.placeName!==void 0&&(i.actualPlaceName=n.placeName)),i}eE();ce();uf();var Tl={query_instances:{discriminator:"action",validActions:new Set(["get","children","find_child","find_descendant","wait_for_child","class_info","search_name","search_class","search_property","search_tag","file_tree","project_structure","descendants","ancestors"]),paramAliases:{query_instances_search_name:{query:"pattern"},query_instances_search_property:{root:"rootPath"},query_instances_search_tag:{root:"rootPath"},query_instances_project_structure:{root:"rootPath"}}},mutate_instances:{discriminator:"action",validActions:new Set(["create","create_with_props","delete","clone","move","rename","pivot","create_tree","mass_create","mass_delete","mass_duplicate","smart_duplicate"]),paramAliases:{mutate_instances_clone:{path:"sourcePath"},mutate_instances_smart_duplicate:{spacing:"offset"}}},manage_properties:{discriminator:"action",validActions:new Set(["get","set","get_all","set_multiple","get_attr","set_attr","get_all_attrs","delete_attr","add_tag","remove_tag","check_tag","get_tags","get_tagged","set_calculated","set_relative","mass_set","mass_get","modify_children"]),paramAliases:{manage_properties_get_tagged:{tagName:"tag",root:"rootPath"},manage_properties_set_relative:{amount:"value"}}},manage_scripts:{discriminator:"action",validActions:new Set(["get_source","set_source","create","delete","edit_replace","edit_insert","edit_delete","search","replace","get_dependencies"]),paramAliases:{manage_scripts_edit_replace:{newLines:"newContent"},manage_scripts_edit_insert:{lines:"content"},manage_scripts_replace:{pattern:"searchPattern"}}},manage_ui:{discriminator:"action",validActions:new Set(["design_brief","create_tree","update","delete","preview","check"])},manage_lighting:{discriminator:"action",validActions:new Set(["lighting","atmosphere","sky","terrain_props","time"])},manage_selection:{discriminator:"action",validActions:new Set(["get","set","clear","cached","context","details","add","remove","watch"])},manage_camera:{discriminator:"action",validActions:new Set(["info","focus_path","focus_position","suggest","screenshot"]),paramAliases:{manage_camera_suggest:{path:"targetPath"}}},manage_tween:{discriminator:"action",validActions:new Set(["create","play","pause","cancel"])},manage_audio:{discriminator:"action",validActions:new Set(["play","stop","pause","resume","set_listener"])},manage_animation:{discriminator:"action",validActions:new Set(["load","play","stop","get_tracks"])},manage_physics:{discriminator:"action",validActions:new Set(["register_group","set_collidable","get_groups"])},manage_effects:{discriminator:"action",validActions:new Set(["emit","clear","toggle"])},manage_terrain:{discriminator:"action",validActions:new Set(["fill_block","fill_ball","fill_cylinder","fill_wedge","clear_region","clear_bounds","replace_material","colors_get","colors_set","read_voxel","read_voxels","write_voxels","generate","smooth"])},spatial_query:{discriminator:"action",validActions:new Set(["raycast","find_ground","check_placement","multi_raycast","scan_area","find_flat","find_spawn","analyze_walkable","spatial_map","find_space","bounds","snap_grid","collision"]),paramAliases:{spatial_query_spatial_map:{path:"rootPath"}}},manage_assets:{discriminator:"action",validActions:new Set(["insert","info","search","search_insert","insert_free","insert_package","export_selection_json","export_selection_rbxm","export_path_rbxm","review_model","generate_model","upload_asset","import_rbxm","generate_thumbnail"]),paramAliases:{manage_assets_search:{maxResults:"limit"}}},manage_open_cloud_assets:{discriminator:"action",validActions:new Set(["credential_status","capabilities","upload","update","info","operation_status"])},manage_sync:{discriminator:"action",validActions:new Set(["status_current_place","history","directions","read_file","write_file","progress"])},workspace_state:{discriminator:"action",validActions:new Set(["sync","snapshot","changes","viewport","clear_history","metadata","scripts","selection_info","clear_cache"])},manage_logs:{discriminator:"action",validActions:new Set(["get","clear","errors"]),paramAliases:{manage_logs_get:{level:"type"}}},system_info:{discriminator:"action",validActions:new Set(["ping","connection","usage","place_info","services","studio_settings"])},manage_studio:{discriminator:"action",validActions:new Set(["toggle_ui_preview","play_start","play_stop","play_pause","play_resume","play_status","run_test"])}};var ome={manage_selection_cached:"internal",manage_open_cloud_assets_credential_status:"internal",manage_open_cloud_assets_capabilities:"internal",manage_open_cloud_assets_upload:"internal",manage_open_cloud_assets_update:"internal",manage_open_cloud_assets_info:"internal",manage_open_cloud_assets_operation_status:"internal",manage_sync_status_current_place:"internal",manage_sync_history:"internal",manage_sync_directions:"internal",manage_sync_read_file:"internal",manage_sync_write_file:"internal",manage_sync_progress:"internal",system_info_connection:"internal",manage_studio_run_test:"internal"};function jx(t){return ome[t]||"plugin"}var yq=new Set(["batch_execute","execute_luau","extended_call_method","extended_call_methods","extended_get_properties","extended_get_property","extended_set_properties","extended_set_property","manage_animation_get_tracks","manage_animation_load","manage_animation_play","manage_animation_stop","manage_assets_export_path_rbxm","manage_assets_export_selection_json","manage_assets_export_selection_rbxm","manage_assets_generate_model","manage_assets_generate_thumbnail","manage_assets_import_rbxm","manage_assets_info","manage_assets_insert","manage_assets_insert_free","manage_assets_insert_package","manage_assets_review_model","manage_assets_search","manage_assets_search_insert","manage_assets_upload_asset","manage_audio_pause","manage_audio_play","manage_audio_resume","manage_audio_set_listener","manage_audio_stop","manage_camera_screenshot","manage_effects_clear","manage_effects_emit","manage_effects_toggle","manage_lighting_atmosphere","manage_lighting_lighting","manage_lighting_sky","manage_lighting_terrain_props","manage_lighting_time","manage_open_cloud_assets_capabilities","manage_open_cloud_assets_credential_status","manage_open_cloud_assets_info","manage_open_cloud_assets_operation_status","manage_open_cloud_assets_update","manage_open_cloud_assets_upload","manage_physics_get_groups","manage_physics_register_group","manage_physics_set_collidable","manage_properties_mass_get","manage_properties_mass_set","manage_properties_modify_children","manage_properties_set_calculated","manage_properties_set_relative","manage_scripts_replace","manage_selection_add","manage_selection_context","manage_selection_details","manage_selection_remove","manage_selection_watch","manage_studio_play_pause","manage_studio_play_resume","manage_studio_play_start","manage_studio_play_status","manage_studio_play_stop","manage_studio_run_test","manage_studio_toggle_ui_preview","manage_sync_directions","manage_sync_history","manage_sync_progress","manage_sync_read_file","manage_sync_status_current_place","manage_sync_write_file","manage_terrain_clear_bounds","manage_terrain_clear_region","manage_terrain_colors_get","manage_terrain_colors_set","manage_terrain_fill_ball","manage_terrain_fill_block","manage_terrain_fill_cylinder","manage_terrain_fill_wedge","manage_terrain_generate","manage_terrain_read_voxel","manage_terrain_read_voxels","manage_terrain_replace_material","manage_terrain_smooth","manage_terrain_write_voxels","manage_tween_cancel","manage_tween_create","manage_tween_pause","manage_tween_play","manage_ui_check","manage_ui_create_tree","manage_ui_delete","manage_ui_design_brief","manage_ui_preview","manage_ui_update","mutate_instances_create_tree","mutate_instances_mass_create","mutate_instances_mass_delete","mutate_instances_mass_duplicate","mutate_instances_smart_duplicate","query_instances_ancestors","query_instances_descendants","query_instances_file_tree","query_instances_project_structure","query_instances_search_property","query_instances_search_tag","spatial_query_analyze_walkable","spatial_query_bounds","spatial_query_check_placement","spatial_query_collision","spatial_query_find_flat","spatial_query_find_ground","spatial_query_find_space","spatial_query_find_spawn","spatial_query_multi_raycast","spatial_query_raycast","spatial_query_scan_area","spatial_query_snap_grid","spatial_query_spatial_map","system_info_place_info","system_info_services","system_info_studio_settings","workspace_state_changes","workspace_state_clear_cache","workspace_state_clear_history","workspace_state_metadata","workspace_state_scripts","workspace_state_selection_info","workspace_state_snapshot","workspace_state_sync","workspace_state_viewport"]),UE=new Set(["system_info_connection","system_info_ping","system_info_usage"]);function zn(t){return yq.has(t)?"pro":"basic"}ki();Mx();import{readFile as Ime}from"node:fs/promises";import kme from"node:path";import{createHash as xme,randomUUID as HE}from"node:crypto";import{mkdir as xf,readFile as Pq,readdir as Rq,rename as Eq,rm as _me,stat as Sme,writeFile as qx}from"node:fs/promises";import zt from"node:path";import{extname as ume}from"node:path";import{stat as dme}from"node:fs/promises";var pme=20*1024*1024,Iq=[{category:"image",assetType:"Image",folder:"images",extensions:[".png",".jpeg",".jpg",".bmp",".tga"],supportsContentUpdate:!1,contentTypes:{".png":"image/png",".jpeg":"image/jpeg",".jpg":"image/jpeg",".bmp":"image/bmp",".tga":"image/tga"}},{category:"decal",assetType:"Decal",folder:"decals",extensions:[".png",".jpeg",".jpg",".bmp",".tga"],supportsContentUpdate:!1,contentTypes:{".png":"image/png",".jpeg":"image/jpeg",".jpg":"image/jpeg",".bmp":"image/bmp",".tga":"image/tga"}},{category:"audio",assetType:"Audio",folder:"audio",extensions:[".mp3",".ogg",".wav",".flac"],supportsContentUpdate:!1,contentTypes:{".mp3":"audio/mpeg",".ogg":"audio/ogg",".wav":"audio/wav",".flac":"audio/flac"}},{category:"mesh",assetType:"Mesh",folder:"meshes",extensions:[".mesh"],supportsContentUpdate:!1,contentTypes:{".mesh":"application/octet-stream"}},{category:"model",assetType:"Model",folder:"models",extensions:[".fbx",".gltf",".glb",".rbxm",".rbxmx"],supportsContentUpdate:!0,contentTypes:{".fbx":"model/fbx",".gltf":"model/gltf+json",".glb":"model/gltf-binary",".rbxm":"model/x-rbxm",".rbxmx":"model/x-rbxm"}},{category:"video",assetType:"Video",folder:"videos",extensions:[".mp4",".mov"],supportsContentUpdate:!1,contentTypes:{".mp4":"video/mp4",".mov":"video/quicktime"}},{category:"animation",assetType:"Animation",folder:"animations",extensions:[".rbxm",".rbxmx"],supportsContentUpdate:!0,contentTypes:{".rbxm":"model/x-rbxm",".rbxmx":"model/x-rbxm"}}],fme=new Map(Iq.map(t=>[t.category,t]));function xq(t){if(!t)throw new Error("Open Cloud asset upload is disabled in WEPPY Dashboard settings.")}function zx(t,e){return t.split(e.apiKey).join("[redacted]")}function qE(t){let e=fme.get(t);if(!e)throw new Error(`Unsupported asset category: ${t}`);return e}function Lx(t){return qE(t)}function _q(t,e){let n=t.creatorType??e.creatorType,i=t.creatorId??e.creatorId;if(!n||!i)throw new Error("creatorType and creatorId are required for Roblox Open Cloud asset upload/update.");return{...t,creatorType:n,creatorId:i}}async function Sq(t,e,n){let i=ume(e).toLowerCase(),r=t.contentTypes[i];if(!r)throw new Error(`Unsupported file extension ${i||"(none)"} for ${t.category}.`);if((await dme(e)).size>n)throw new Error(`Asset file is too large. Maximum size is ${n} bytes.`);return r}function wq(t){return typeof t.path=="string"&&t.path.startsWith("operations/")?t.path:null}function Cq(t,e,n,i){let r={apiKey:t.apiKey,operationId:e};return n!==void 0&&(r.intervalMs=n),i!==void 0&&(r.timeoutMs=i),r}var Al=class{client;credentialStore;isOpenCloudUploadEnabled;maxFileSizeBytes;constructor(e){this.client=e.client,this.credentialStore=e.credentialStore,this.isOpenCloudUploadEnabled=e.isOpenCloudUploadEnabled,this.maxFileSizeBytes=e.maxFileSizeBytes??pme}getCapabilities(){return Iq.map(({contentTypes:e,...n})=>n)}async uploadAsset(e){xq(this.isOpenCloudUploadEnabled());let n=await this.getRequiredCredential(),i=_q(e,n),r=qE(i.category),a=await Sq(r,i.filePath,this.maxFileSizeBytes);try{let o={apiKey:n.apiKey,assetType:r.assetType,displayName:i.displayName,description:i.description??"",creatorType:i.creatorType,creatorId:i.creatorId,filePath:i.filePath,contentType:a};i.expectedPrice!==void 0&&(o.expectedPrice=i.expectedPrice);let s=await this.client.createAsset(o);if(i.waitForOperation){let c=wq(s);return c?await this.client.pollOperation(Cq(n,c,i.operationPollIntervalMs,i.operationPollTimeoutMs)):s}return s}catch(o){throw new Error(zx(o instanceof Error?o.message:String(o),n))}}async updateAsset(e){xq(this.isOpenCloudUploadEnabled());let n=await this.getRequiredCredential(),i=_q(e,n),r=qE(i.category),a;if(i.filePath){if(!r.supportsContentUpdate)throw new Error(`${r.category} assets do not support content updates.`);a=await Sq(r,i.filePath,this.maxFileSizeBytes)}try{let o={apiKey:n.apiKey,assetId:i.assetId,assetType:r.assetType,creatorType:i.creatorType,creatorId:i.creatorId};i.filePath&&(o.filePath=i.filePath),a!==void 0&&(o.contentType=a),i.displayName!==void 0&&(o.displayName=i.displayName),i.description!==void 0&&(o.description=i.description),i.updateMask!==void 0&&(o.updateMask=i.updateMask),i.expectedPrice!==void 0&&(o.expectedPrice=i.expectedPrice);let s=await this.client.updateAsset(o);if(i.waitForOperation){let c=wq(s);return c?await this.client.pollOperation(Cq(n,c,i.operationPollIntervalMs,i.operationPollTimeoutMs)):s}return s}catch(o){throw new Error(zx(o instanceof Error?o.message:String(o),n))}}async getAsset(e){let n=await this.getRequiredCredential();try{let i={apiKey:n.apiKey,assetId:e.assetId};return e.readMask!==void 0&&(i.readMask=e.readMask),await this.client.getAsset(i)}catch(i){throw new Error(zx(i instanceof Error?i.message:String(i),n))}}async getOperation(e){let n=await this.getRequiredCredential();try{return await this.client.getOperation({apiKey:n.apiKey,operationId:e.operationId})}catch(i){throw new Error(zx(i instanceof Error?i.message:String(i),n))}}async getRequiredCredential(){let e=await this.credentialStore.getCredentialForUse();if(!e)throw new Error("Configure a Roblox Open Cloud API key in WEPPY Dashboard before using Open Cloud asset upload.");return e}};import kq from"node:fs";import Jt from"node:path";Ob();var mme=/^asset_(image|decal|audio|mesh|model|video|animation)_\d+_[a-z0-9]+$/;function gme(t){if(!Number.isInteger(t)||t<0)throw new Error(`Invalid place ID: ${t}`)}function hme(t,e){try{return kq.statSync(Jt.join(t,e,".sync-meta.json")).isFile()}catch{return!1}}function yme(t,e){gme(e.placeId);let n=`place_${e.placeId}`,i=e.placeName?ol(e.placeName):"",r=i?`${n}_${i}`:n,a=[];try{let o=new RegExp(`^place_${e.placeId}(?:_.*)?$`);a=kq.readdirSync(t,{withFileTypes:!0}).filter(s=>s.isDirectory()&&o.test(s.name)).map(s=>s.name).sort()}catch{return r}return i&&a.includes(r)?r:a.find(o=>hme(t,o))??(a.includes(r)?r:null)??a[0]??r}function BE(t){let e=Jt.resolve(t.projectSyncRoot),n=Lx(t.category).folder,i=t.scope.kind==="place"?Jt.join(e,yme(e,t.scope),"assets",n):Jt.join(e,"shared-assets",n);return{root:i,inbox:Jt.join(i,"inbox"),index:Jt.join(i,".asset-library-index.json")}}function vme(t){let e=mme.exec(t);return e?.[1]?e[1]:null}function yf(t,e){let n=vme(t);return n?e?n===e:!0:!1}function Ux(t,e){if(!yf(t,e))throw new Error(`Invalid asset ID: ${t}`)}function Yr(t,e){let n=Jt.relative(Jt.resolve(t),Jt.resolve(e));return n===""||!n.startsWith("..")&&!Jt.isAbsolute(n)}function bme(t){Ux(t.assetId,t.category);let e=BE(t),n=Jt.resolve(e.root,t.assetId);if(!Yr(e.root,n))throw new Error(`Invalid asset path for ${t.assetId}`);return n}function Fx(t){let e=bme(t),n=Jt.resolve(e,t.relativeFileName);if(!Yr(e,n))throw new Error(`Invalid asset file path for ${t.assetId}`);return n}function vf(t,e){return Jt.relative(Jt.resolve(t),Jt.resolve(e)).split(Jt.sep).join("/")}var Tq=20*1024*1024,wme=200;function Aq(t,e){return t.kind!==e.kind?!1:t.kind==="shared"&&e.kind==="shared"?!0:t.kind==="place"&&e.kind==="place"&&t.placeId===e.placeId}function $q(t,e){let n=zt.extname(t).toLowerCase(),i=Lx(e);if(!i.extensions.includes(n))return null;let r=i.contentTypes[n];return r?{canonicalExt:n,mimeType:r}:null}function ZE(t,e,n){if(e!=="image"&&e!=="decal")return!0;let i=zt.extname(t).toLowerCase();return i===".png"?n.length>=8&&n[0]===137&&n[1]===80&&n[2]===78&&n[3]===71&&n[4]===13&&n[5]===10&&n[6]===26&&n[7]===10:i===".jpg"||i===".jpeg"?n.length>=3&&n[0]===255&&n[1]===216&&n[2]===255:i===".bmp"?n.length>=2&&n[0]===66&&n[1]===77:i===".tga"?n.length>0:!1}function Oq(t){return xme("sha256").update(t).digest("hex")}function Bx(t){return t.now?.()??Date.now()}function Cme(t){return(t.randomId?.()??HE().replace(/-/g,"").slice(0,6)).toLowerCase().replace(/[^a-z0-9]/g,"").slice(0,12)||"asset"}function Dq(t,e){let n=Math.floor(Bx(t)/1e3);for(let i=0;i<20;i++){let r=Cme(t),a=i===0?`asset_${t.category}_${n}_${r}`:`asset_${t.category}_${n}_${r}${i}`;if(!e.has(a))return a}return`asset_${t.category}_${n}_${HE().replace(/-/g,"").slice(0,10)}`}function Nq(t){let e=zt.parse(t).name.trim();return e.length>0?e:t}function jq(t){if(t.mimeType!=="image/png")throw new Error("Asset Library preview must be an image/png thumbnail");if(zt.basename(t.fileName).toLowerCase()!=="thumbnail.png")throw new Error("Asset Library preview file must be thumbnail.png");if(!ZE("thumbnail.png","image",t.content))throw new Error("Asset Library preview is not a valid PNG file");return{fileName:"thumbnail.png",content:t.content}}async function VE(t,e){let n=`${t}.tmp.${HE().slice(0,8)}`;await qx(n,JSON.stringify(e,null,2),"utf8"),await Eq(n,t)}async function Mq(t,e){try{let n=await Pq(zt.join(e,"asset.json"),"utf8"),i=JSON.parse(n);return!yf(i.id,t.category)||i.category!==t.category||!Aq(i.scope,t.scope)?null:i}catch{return null}}async function bf(t,e){let n;try{n=await Rq(e.root,{withFileTypes:!0})}catch(r){if(r?.code==="ENOENT")return[];throw r}let i=[];for(let r of n.sort((a,o)=>a.name.localeCompare(o.name))){if(!r.isDirectory()||!yf(r.name,t.category))continue;let a=zt.join(e.root,r.name),o=await Mq(t,a);o&&i.push(o)}return i.sort((r,a)=>a.createdAt.localeCompare(r.createdAt)||a.id.localeCompare(r.id))}async function $l(t,e,n){if(Ux(n.id,t.category),n.category!==t.category||!Aq(n.scope,t.scope))throw new Error(`Asset metadata does not match library scope/category: ${n.id}`);let i=zt.join(e.root,n.id);if(!Yr(e.root,i))throw new Error(`Invalid asset path for ${n.id}`);await xf(i,{recursive:!0}),await VE(zt.join(i,"asset.json"),n)}async function zq(t,e){await xf(t.root,{recursive:!0});let n={version:1,generatedAt:new Date().toISOString(),assets:e.map(i=>i.id)};await VE(t.index,n)}function Ti(t,e,n){return{fileName:t,reason:e,message:n}}async function Xr(t){let e=BE(t);return await xf(e.inbox,{recursive:!0}),e}async function Lq(t){let e=await Xr(t),n=await bf(t,e);return await zq(e,n),n}async function Lt(t,e){Ux(e,t.category);let n=await Xr(t),i=zt.join(n.root,e);if(!Yr(n.root,i))throw new Error(`Invalid asset path for ${e}`);let r=await Mq(t,i);if(!r)throw new Error(`Asset not found: ${e}`);return r}async function Ol(t){let e=await Xr(t),n=await bf(t,e),i={version:1,generatedAt:new Date().toISOString(),assets:n.map(r=>r.id)};return await VE(e.index,i),i}async function Uq(t){let e=await Xr(t),n=await bf(t,e),i=new Set(n.map(p=>p.id)),r=new Set(n.map(p=>p.file.sha256)),a=[],o=[],s=t.maxFileSizeBytes??Tq,c=t.maxFilesPerRescan??wme,l;try{l=await Rq(e.inbox,{withFileTypes:!0})}catch(p){if(p?.code==="ENOENT")l=[];else throw p}let u=l.sort((p,f)=>p.name.localeCompare(f.name));for(let p=0;p<u.length;p++){let f=u[p];if(p>=c){o.push(Ti(f.name,"maxFileCount","rescan file count limit exceeded"));continue}if(f.name.startsWith(".")){o.push(Ti(f.name,"hidden","hidden or system file"));continue}if(f.isSymbolicLink()){o.push(Ti(f.name,"symlink","symlink files are not followed"));continue}if(f.isDirectory()){o.push(Ti(f.name,"nestedDirectory","nested directories are not scanned"));continue}if(!f.isFile()){o.push(Ti(f.name,"unsupportedType","unsupported inbox entry type"));continue}let m=$q(f.name,t.category);if(!m){o.push(Ti(f.name,"unsupportedType",`unsupported ${t.category} extension`));continue}let g=zt.join(e.inbox,f.name),h=await Sme(g);if(h.size>s){o.push(Ti(f.name,"oversized","asset file is larger than the configured limit"));continue}let v=await Pq(g);if(!ZE(f.name,t.category,v)){o.push(Ti(f.name,"invalidSignature","file signature does not match the extension"));continue}let x=Oq(v);if(r.has(x)){o.push(Ti(f.name,"duplicate","asset content already exists in Asset Library"));continue}let _=Dq(t,i);i.add(_),r.add(x);let I=zt.join(e.root,_),w=`original${m.canonicalExt}`;await xf(I,{recursive:!0}),await Eq(g,zt.join(I,w));let D=new Date(Bx(t)).toISOString(),M={version:1,id:_,category:t.category,scope:t.scope,status:"localOnly",displayName:Nq(f.name),description:"",source:{kind:"generated",originalPath:vf(t.projectSyncRoot,g)},file:{original:w,preview:null,mimeType:m.mimeType,sha256:x,sizeBytes:h.size,width:null,height:null,durationMs:null},roblox:{uploaded:!1},usage:{lastScannedAt:null,scanSource:null,references:[]},createdAt:D,updatedAt:D};await $l(t,e,M),a.push(M)}let d=await bf(t,e);return await zq(e,d),{assets:d,adopted:a,skipped:o,adoptedCount:a.length,skippedCount:o.length}}async function Fq(t){let e=await Xr(t),n=$q(t.originalFileName,t.category);if(!n)throw new Error(`Unsupported ${t.category} extension for Asset Library export`);let i=t.maxFileSizeBytes??Tq;if(t.content.length>i)throw new Error("asset file is larger than the configured limit");if(!ZE(t.originalFileName,t.category,t.content))throw new Error("file signature does not match the extension");let r=await bf(t,e),a=Oq(t.content),o=r.find(h=>h.file.sha256===a);if(o)return{asset:o,deduplicated:!0};let s=new Set(r.map(h=>h.id)),c=Dq(t,s),l=zt.join(e.root,c);if(!Yr(e.root,l))throw new Error(`Invalid asset path for ${c}`);let u=`original${n.canonicalExt}`;await xf(l,{recursive:!0}),await qx(zt.join(l,u),t.content);let d=null;if(t.preview){let h=jq(t.preview);d=h.fileName,await qx(zt.join(l,h.fileName),h.content)}let p=new Date(Bx(t)).toISOString(),f=t.roblox??{uploaded:!1},m=f.uploaded&&f.assetId?"uploaded":"localOnly",g={version:1,id:c,category:t.category,scope:t.scope,status:m,displayName:t.displayName?.trim()||Nq(t.originalFileName),description:t.description??"",source:{...t.source,originalPath:vf(t.projectSyncRoot,zt.join(l,u))},file:{original:u,preview:d,mimeType:n.mimeType,sha256:a,sizeBytes:t.content.length,width:null,height:null,durationMs:null},roblox:f,usage:{lastScannedAt:null,scanSource:null,references:[]},...t.rbxm?{rbxm:t.rbxm}:{},createdAt:p,updatedAt:p};return await $l(t,e,g),await Ol(t),{asset:g,deduplicated:!1}}async function qq(t){let e=await Xr(t),n=await Lt(t,t.assetId),i=jq(t.preview),r=Fx({...t,relativeFileName:i.fileName});await qx(r,i.content);let a={...n,file:{...n.file,preview:i.fileName},...n.rbxm&&t.rbxmThumbnail?{rbxm:{...n.rbxm,thumbnail:t.rbxmThumbnail}}:{},updatedAt:new Date(Bx(t)).toISOString()};return await $l(t,e,a),await Ol(t),{asset:a}}async function Bq(t,e,n){let i=await Xr(t),r=await Lt(t,e),a={...r,displayName:typeof n.displayName=="string"?n.displayName:r.displayName,description:typeof n.description=="string"?n.description:r.description,source:{...r.source,...n.source?.agent!==void 0?{agent:n.source.agent}:{},...n.source?.contextId!==void 0?{contextId:n.source.contextId}:{},...n.source?.prompt!==void 0?{prompt:n.source.prompt}:{}},updatedAt:new Date().toISOString()};return await $l(t,i,a),await Ol(t),a}async function Hq(t,e,n){let i=await Xr(t),a={...await Lt(t,e),usage:n,updatedAt:new Date().toISOString()};return await $l(t,i,a),await Ol(t),a}async function Zq(t,e){let n=await Xr(t);await Lt(t,e);let i=zt.join(n.root,e);if(!Yr(n.root,i))throw new Error(`Invalid asset path for ${e}`);return await _me(i,{recursive:!0}),await Ol(t),{assetId:e,removed:1}}async function Ha(t){let e=await Xr(t);return await $l(t,e,t.asset),await Ol(t),t.asset}async function Dl(t){let e=await Lt(t,t.assetId);return Fx({...t,relativeFileName:e.file.original})}async function Vq(t){let e=await Lt(t,t.assetId);return Fx({...t,relativeFileName:e.file.preview??e.file.original})}var Pme="https://create.roblox.com/dashboard/creations/store",Rme="manage_assets_import_rbxm",GE="manage_assets_generate_thumbnail",Eme="manage_assets_review_model";var KE=new Set([Rme,GE]),JE=new Set(["manage_assets_export_selection_rbxm","manage_assets_export_path_rbxm",Eme]),Tme=new Set(["model","animation"]);function Qe(t){return t&&typeof t=="object"?t:null}function Ame(t){if(typeof t!="string"||!Tme.has(t))throw new Error(`Unsupported Asset Library .rbxm round-trip category: ${String(t??"(missing)")}`);return t}function $me(t){if(typeof t=="number"&&Number.isInteger(t)&&t>=0)return t;if(typeof t=="string"&&t.trim().length>0){let e=Number.parseInt(t,10);if(Number.isInteger(e)&&e>=0)return e}return null}function Wq(t,e){for(let n of t.pluginClients.values())if(!(typeof n.placeId!="number"||!Number.isFinite(n.placeId))&&!(e!==void 0&&n.placeId!==e))return{placeId:n.placeId,...n.placeName?{placeName:n.placeName}:{}};return null}function YE(t,e){let n=mt(t.config.dataDir),i=Ame(e.category),r=typeof e.scope=="string"?e.scope:"place",a=typeof e.assetLibraryAssetId=="string"&&e.assetLibraryAssetId.length>0?e.assetLibraryAssetId:void 0;if(r==="shared")return{projectSyncRoot:n,scope:{kind:"shared"},category:i,...a?{assetId:a}:{}};if(r!=="place")throw new Error(`Invalid Asset Library scope: ${r}`);let o=$me(e.placeId),s=t.syncController?.getDefaultRuntimePlaceId()??null,c=o??s??Wq(t)?.placeId??null;if(c===null)throw new Error("No placeId is available for Asset Library .rbxm round-trip.");let l=Wq(t,c);return{projectSyncRoot:n,scope:{kind:"place",placeId:c,...l?.placeName?{placeName:l.placeName}:{}},category:i,...a?{assetId:a}:{}}}function Ome(t){if(kme.extname(t.file.original).toLowerCase()!==".rbxm")throw new Error(`Asset Library Studio round-trip supports original.rbxm only. Unsupported original file: ${t.file.original}`)}function Dme(t,e){if(typeof t!="string"||t.trim().length===0)throw new Error(`${e} is missing`);return Buffer.from(t,"base64")}function Nme(t,e){let n=Qe(e),r={kind:n?.kind==="generation"||typeof t.prompt=="string"?"generated":"studioExport",originalPath:"studio:selection"};if(n){let a=typeof n.path=="string"?n.path:typeof n.kind=="string"?n.kind:void 0;a&&(r.originalPath=`studio:${a}`);let o=ge(n.prompt,1e3);o&&(r.prompt=o)}if(!r.prompt){let a=ge(t.prompt,1e3);a&&(r.prompt=a)}return typeof t.contextId=="string"&&(r.contextId=t.contextId),r}function Yq(t){let e=Qe(t);if(!e)return;let n={};typeof e.width=="number"&&(n.width=e.width),typeof e.height=="number"&&(n.height=e.height),typeof e.source=="string"&&(n.source=e.source),typeof e.error=="string"&&(n.error=e.error);let i=_f(e.attempts);return i.length>0&&(n.attempts=i),Object.keys(n).length>0?n:void 0}function ge(t,e){return typeof t!="string"?null:t.slice(0,e)}function jme(t){if(typeof t!="string")return null;let e=t.trim();return/^\d+$/.test(e)?e:null}function Gq(t){return`rbxassetid://${t}`}function Kq(t){return`${Pme}/${t}/configure`}function Jq(t){return`assets/${t}`}function rr(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Xq(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.name,256),r=ge(n.className,128),a=ge(n.path,512);return i===null||r===null||a===null?[]:[{name:i,className:r,path:a}]}):[]}function Mme(t){let e=Qe(t);if(!e)return{};let n={};for(let[i,r]of Object.entries(e).slice(0,100))typeof r!="number"||!Number.isFinite(r)||r<0||(n[i.slice(0,128)]=Math.floor(r));return n}function zme(t){return Array.isArray(t)?t.slice(0,200).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.path,512),r=ge(n.property,128),a=ge(n.value,1024);if(i===null||r===null||a===null)return[];let o=ge(n.assetId,64);return[{path:i,property:r,value:a,...o?{assetId:o}:{}}]}):[]}function _f(t){return Array.isArray(t)?t.slice(0,8).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.method,80),r=n.status==="success"||n.status==="failed"||n.status==="skipped"?n.status:null;if(i===null||r===null)return[];let a=ge(n.message,512);return[{method:i,status:r,...a?{message:a}:{}}]}):[]}function Lme(t,e){let n=t.thumbnailMode==="auto"?"auto":"none";if(n==="none")return{mode:n,status:"skipped",message:"Thumbnail generation disabled"};let i=Yq(e),r=Qe(e),a=typeof r?.pngBase64=="string"&&r.pngBase64.length>0,o=typeof r?.base64Rgba=="string"&&r.base64Rgba.length>0&&r.format==="rgba8"&&typeof r.width=="number"&&typeof r.height=="number";if(i&&(a||o)){let s=rr(i.width),c=rr(i.height),l=_f(r?.attempts);return{mode:n,status:"generated",...s!==void 0?{width:s}:{},...c!==void 0?{height:c}:{},...typeof i.source=="string"?{source:i.source.slice(0,128)}:{},...l.length>0?{attempts:l}:{}}}if(i&&typeof i.error=="string"){let s=_f(Qe(e)?.attempts);return{mode:n,status:"failed",message:i.error.slice(0,512),...s.length>0?{attempts:s}:{}}}return{mode:n,status:"skipped",message:"Thumbnail was not returned"}}function Ume(t,e){let n=Qe(t);if(!n)return e;let i=n.mode==="auto"||n.mode==="none"?n.mode:e.mode,r=n.status==="generated"||n.status==="skipped"||n.status==="failed"?n.status:e.status,a=ge(n.message,512),o=rr(n.width),s=rr(n.height),c=ge(n.source,128),l=_f(n.attempts);return{mode:i,status:r,...a?{message:a}:{},...o!==void 0?{width:o}:{},...s!==void 0?{height:s}:{},...c?{source:c}:{},...l.length>0?{attempts:l}:{}}}function WE(t,e=0){if(e>3)return;if(typeof t=="string")return t.slice(0,512);if(typeof t=="boolean")return t;if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(Array.isArray(t))return t.slice(0,50).flatMap(r=>{let a=WE(r,e+1);return a===void 0?[]:[a]});let n=Qe(t);if(!n)return;let i={};for(let[r,a]of Object.entries(n).slice(0,50)){let o=WE(a,e+1);o!==void 0&&(i[r.slice(0,128)]=o)}return i}function Fme(t){let e=Qe(t),n=rr(e?.x),i=rr(e?.y),r=rr(e?.z);if(!(n===void 0||i===void 0||r===void 0))return{x:n,y:i,z:r}}function qme(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=n.severity==="info"||n.severity==="warning"||n.severity==="error"?n.severity:null,r=ge(n.category,80),a=ge(n.code,120),o=ge(n.path,512),s=ge(n.message,512);if(!i||r===null||a===null||o===null||s===null)return[];let c=ge(n.suggestion,512);return[{severity:i,category:r,code:a,path:o,message:s,...c?{suggestion:c}:{}}]}):[]}function Bme(t){let e=Qe(t);if(!e)return;let n=e.readiness==="ready"||e.readiness==="review"||e.readiness==="blocked"?e.readiness:null;if(!n)return;let i=WE(e.summary),r=ge(e.reviewedAt,64),a=Xq(e.roots);return{readiness:n,...r?{reviewedAt:r}:{},...a.length>0?{roots:a}:{},summary:Qe(i)??{},findings:qme(e.findings)}}function Hme(t){let e=Qe(t);if(!e)return;let n={};for(let[i,r]of Object.entries(e).slice(0,16))typeof r=="string"&&(n[i.slice(0,128)]=r.slice(0,256)),typeof r=="number"&&Number.isFinite(r)&&(n[i.slice(0,128)]=r),typeof r=="boolean"&&(n[i.slice(0,128)]=r);return Object.keys(n).length>0?n:void 0}function Zme(t){let e=Qe(t);if(!e)return;let n=ge(e.provider,120);if(!n)return;let i=ge(e.generatedAt,64),r=ge(e.prompt,1e3),a=e.schemaMode==="predefined"||e.schemaMode==="custom"?e.schemaMode:void 0,o=e.predefinedSchema==="Body1"||e.predefinedSchema==="Car5"?e.predefinedSchema:void 0,s=Array.isArray(e.schemaGroups)?e.schemaGroups.slice(0,50).flatMap(f=>{let m=ge(f,120);return m?[m]:[]}):void 0,c=Fme(e.requestedSize),l=rr(e.maxTriangles),u=ge(e.targetParent,512),d=ge(e.path,512),p=Hme(e.metadata);return{provider:n,...i?{generatedAt:i}:{},...r?{prompt:r}:{},...a?{schemaMode:a}:{},...o?{predefinedSchema:o}:{},...s&&s.length>0?{schemaGroups:s}:{},...c?{requestedSize:c}:{},...l!==void 0?{maxTriangles:Math.floor(l)}:{},...typeof e.generateTextures=="boolean"?{generateTextures:e.generateTextures}:{},...u?{targetParent:u}:{},...d?{path:d}:{},...p?{metadata:p}:{}}}function Vme(t){return Array.isArray(t)?t.slice(0,100).flatMap(e=>{let n=Qe(e);if(!n)return[];let i=ge(n.path,512),r=n.assetType==="Mesh"||n.assetType==="Image"||n.assetType==="Model"?n.assetType:null,a=n.status==="uploaded"||n.status==="failed"?n.status:null;if(i===null||r===null||a===null)return[];let o=ge(n.assetId,64),s=ge(n.assetUri,128),c=n.creatorType==="user"||n.creatorType==="group"?n.creatorType:void 0,l=ge(n.creatorId,64),u=ge(n.sourceProperty,128),d=ge(n.uploadedAt,64),p=ge(n.message,512);return[{path:i,assetType:r,status:a,...o?{assetId:o}:{},...s?{assetUri:s}:{},...c?{creatorType:c}:{},...l?{creatorId:l}:{},...u?{sourceProperty:u}:{},...d?{uploadedAt:d}:{},...p?{message:p}:{}}]}):[]}function Wme(t){let e=Qe(t);if(!e||e.uploaded!==!0)return;let n=jme(e.assetId);if(!n)return;let i=ge(e.uploadedAt,64)??new Date().toISOString(),r=e.creatorType==="user"||e.creatorType==="group"?e.creatorType:void 0,a=ge(e.creatorId,64);return{uploaded:!0,assetId:n,assetUri:Gq(n),assetWebUrl:Kq(n),remotePath:Jq(n),uploadedAt:i,uploadAttempts:[{startedAt:i,finishedAt:i,status:"uploaded",assetRole:"primary",...r?{creatorType:r}:{},...a?{creatorId:a}:{},assetId:n,assetUri:Gq(n),assetWebUrl:Kq(n),remotePath:Jq(n)}]}}function Gme(t){let e=Qe(t.value),n=Xq(e?.roots),i=Mme(e?.classCounts),r=zme(e?.resourceReferences),a=Bme(e?.review),o=Zme(e?.generation),s=Vme(e?.studioUploads),c=rr(e?.exportedCount)??rr(t.exportedCount)??n.length;return{exportedCount:Math.max(0,Math.floor(c)),roots:n,classCounts:i,resourceReferences:r,thumbnail:Ume(e?.thumbnail,t.fallbackThumbnail),...a?{review:a}:{},...o?{generation:o}:{},...s.length>0?{studioUploads:s}:{}}}function Kme(t){return t.length>=8&&t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71&&t[4]===13&&t[5]===10&&t[6]===26&&t[7]===10}function Qq(t){let e=Qe(t);if(!e)return;let n=null;if(typeof e.pngBase64=="string"&&e.pngBase64.length>0?n=Buffer.from(e.pngBase64,"base64"):typeof e.base64Rgba=="string"&&e.base64Rgba.length>0&&e.format==="rgba8"&&typeof e.width=="number"&&typeof e.height=="number"&&(n=Buffer.from(bq(e.base64Rgba,e.width,e.height),"base64")),!!n){if(!Kme(n))throw new Error("Thumbnail payload is not a valid PNG image.");return{fileName:"thumbnail.png",content:n,mimeType:"image/png"}}}function Jme(t,e){let n=e instanceof Error?e.message:String(e);return t.thumbnail.status!=="generated"?t:{...t,thumbnail:{...t.thumbnail,status:"failed",message:`Thumbnail payload could not be stored: ${n}`.slice(0,512)}}}async function eB(t){if(!KE.has(t.command))return t.params;let e=YE(t.ctx,t.params);if(!e.assetId)throw new Error("assetLibraryAssetId is required for Asset Library .rbxm round-trip.");let n=await Lt(e,e.assetId);Ome(n);let i=await Dl({...e,assetId:n.id}),r=await Ime(i);return{...t.params,__assetLibraryRbxmBase64:r.toString("base64"),__assetLibraryOriginalFile:n.file.original}}async function tB(t){if(!JE.has(t.command)||!t.result.success)return t.result;let e=Qe(t.result.data);if(!e||typeof e.rbxmBase64!="string"||e.rbxmBase64.trim().length===0)return t.result;let n=YE(t.ctx,t.params),i=Dme(e.rbxmBase64,"Asset Library .rbxm export payload"),r=typeof t.params.displayName=="string"?t.params.displayName:void 0,a=typeof t.params.description=="string"?t.params.description:void 0,o=`${r?.trim()||"studio-export"}.rbxm`,s,c=null;try{s=Qq(e.thumbnail)}catch(f){c=f,s=void 0}let l=Gme({value:e.rbxm,exportedCount:e.exportedCount,fallbackThumbnail:Lme(t.params,e.thumbnail)});c&&(l=Jme(l,c));let u=Wme(e.roblox),d=await Fq({projectSyncRoot:n.projectSyncRoot,scope:n.scope,category:n.category,originalFileName:o,content:i,...r!==void 0?{displayName:r}:{},...a!==void 0?{description:a}:{},source:Nme(t.params,e.source),...s?{preview:s}:{},rbxm:l,...u?{roblox:u}:{}}),p=Yq(e.thumbnail);return{...t.result,data:{asset:d.asset,deduplicated:d.deduplicated,...typeof e.byteLength=="number"?{byteLength:e.byteLength}:{},...typeof e.exportedCount=="number"?{exportedCount:e.exportedCount}:{},...e.source!==void 0?{source:e.source}:{},...p?{thumbnail:p}:{}}}}async function nB(t){if(!t.result.success)return t.result;let e=Qe(t.result.data),n=Qe(e?.thumbnail),i;try{i=Qq(n)}catch(d){return{...t.result,success:!1,error:d instanceof Error?d.message:String(d)}}if(!n||!i)return{...t.result,success:!1,error:typeof n?.error=="string"?n.error:"Thumbnail payload is missing from Asset Library thumbnail generation result."};let r=rr(n.width),a=rr(n.height),o=ge(n.source,128),s=_f(n.attempts),c={mode:"auto",status:"generated",...r!==void 0?{width:r}:{},...a!==void 0?{height:a}:{},...o?{source:o}:{},...s.length>0?{attempts:s}:{}},l=YE(t.ctx,t.params);if(!l.assetId)throw new Error("assetLibraryAssetId is required for Asset Library thumbnail generation.");let u=await qq({projectSyncRoot:l.projectSyncRoot,scope:l.scope,category:l.category,assetId:l.assetId,preview:i,rbxmThumbnail:c});return{...t.result,data:{asset:u.asset,...r!==void 0?{width:r}:{},...a!==void 0?{height:a}:{},...o?{source:o}:{}}}}function Yme(t){if(t===null||typeof t!="object")return;let e=t.proFallback;if(e===null||typeof e!="object")return;let n=e;if(typeof n.executedCommand!="string")return;let i=Array.isArray(n.alternatives)?n.alternatives.filter(r=>typeof r=="string"):void 0;return{executedCommand:n.executedCommand,...typeof n.requestedCommand=="string"?{requestedCommand:n.requestedCommand}:{},...i?{alternatives:i}:{}}}var Xme=/^Pro action '[^']+' is blocked in Basic mode\. Basic fallback '([^']+)' failed: (.*)$/s,Qme=/^Pro action '[^']+' is blocked in Basic mode\.(?! Basic fallback ')/,ege=/instance not found|not found in|parent not found/,tge=/is required|missing required/,nge=/unknown action|unknown command/,rge=/must be|invalid|cannot/;function ige(t){let e=Xme.exec(t);return e?{fallbackCommand:e[1],reason:e[2]}:null}function age(t){return Qme.test(t)}function oge(t){let e=t.toLowerCase();return ege.test(e)?"not_found":tge.test(e)?"missing_param":nge.test(e)?"unknown_action":rge.test(e)?"validation":"other"}function XE(t){return t.errorType==="bridge_error"||t.errorType==="command_timeout"||t.errorType==="plugin_runtime"||t.errorType==="exception"||t.errorType==="device_blocked"||t.failureOrigin==="bridge"||t.failureOrigin==="plugin_runtime"||t.failureOrigin==="server_exception"||t.failureOrigin==="product_bug"||t.failureOrigin==="unknown"||t.recoverability==="retry"||t.recoverability==="wait_connection"||t.recoverability==="unknown"?"error":"warning"}function Nl(t){if(t.resultSuccess){let e=Yme(t.resultData);return e?{kind:"success_fallback",fallbackCommand:e.executedCommand,...e.alternatives?{alternatives:e.alternatives}:{}}:{kind:"success_ok"}}if(!t.resultError)return{kind:"error"};if(t.tier==="pro"){let e=ige(t.resultError);if(e)return{kind:"blocked_fallback_failed",fallbackCommand:e.fallbackCommand,blockedDetail:oge(e.reason)};if(age(t.resultError))return{kind:"blocked_unsupported"}}return t.failureClassification?{kind:XE(t.failureClassification)}:{kind:"error"}}function we(t,e,n,i,r={}){return{errorType:t,errorDetail:e,failureOrigin:n,recoverability:i,...r}}function sge(t){let e=t.toLowerCase();return/^\s*compilation error:/.test(e)?we("execution_failed","compile_error","agent_request","code_fix",{validationStage:"plugin_handler"}):/^\s*result too large:/.test(e)?we("execution_failed","result_too_large","agent_request","code_fix",{validationStage:"plugin_handler"}):/^\s*execution timed out after/.test(e)?we("execution_failed","execution_timeout","agent_request","code_fix",{validationStage:"plugin_handler"}):/potentially dangerous infinite loop|blocked in sandbox|access to .* is blocked|forbidden|not allowed|cannot access/.test(e)?we("execution_failed","blocked_source","roblox_policy","code_fix",{validationStage:"plugin_handler"}):null}function rB(t){let e=t.toLowerCase();return/upstream_server_down/.test(e)?we("bridge_error","upstream_down","bridge","wait_connection"):/^http [45]\d\d/.test(e)?we("bridge_error","http_error","bridge","retry"):/duplicate request\s*id/.test(e)?we("bridge_error","duplicate_request_id","bridge","code_fix"):/timeout/.test(e)?we("command_timeout","timeout","bridge","retry"):/econnrefused|socket hang up|econnreset|epipe|network/.test(e)?we("bridge_error","connection","bridge","wait_connection"):/abort/.test(e)?we("command_timeout","aborted","bridge","retry"):/runtime error|traceback|attempt to/.test(e)?we("plugin_runtime","runtime_error","plugin_runtime","code_fix"):/created instance, but failed to set \d+ propert/.test(e)?we("execution_failed","property_apply_failed","agent_request","fix_params",{validationStage:"plugin_handler",partialSuccess:"true"}):/failed to set property/.test(e)?we("execution_failed","property_apply_failed","agent_request","fix_params",{validationStage:"plugin_handler"}):/parent(?: instance)? not found/.test(e)?we("execution_failed","parent_not_found","agent_request","fix_params",{validationStage:"plugin_handler"}):/(?:instance|path|root|source instance|ancestor instance) not found|target\s+(?:path\s+)?(?:['"`][^'"`]+['"`]\s+)?not found|not found in|no synced file found for instance/.test(e)?we("execution_failed","not_found","user_project_state","fix_params",{validationStage:"plugin_handler"}):/is required|missing required/.test(e)?we("execution_failed","missing_param","agent_request","fix_params",{validationStage:"schema"}):/invalid classname|invalid class/.test(e)?we("execution_failed","invalid_class","agent_request","fix_params",{validationStage:"plugin_handler"}):/unknown action|unknown command/.test(e)?we("execution_failed","unknown_action","agent_request","fix_params",{validationStage:"dispatcher"}):/failed to insert asset/.test(e)?we("execution_failed","asset_error","roblox_policy","fix_params",{validationStage:"roblox_api"}):/failed to read property|property access denied/.test(e)?we("execution_failed","property_error","agent_request","fix_params",{validationStage:"plugin_handler"}):/forbidden (?:path|parent path)|exceeds (?:total lines|max(?:imum)?(?: length)?)|is not (?:a|an) /.test(e)?we("execution_failed","validation","agent_request","fix_params",{validationStage:"plugin_handler"}):/sync controller not available|project sync is not initialized|no active sync place|not found in sync cache/.test(e)?we("execution_failed","sync_not_ready","user_project_state","wait_connection",{validationStage:"preflight"}):/cannot capture edit-mode screenshot while a playtest is active|play-mode screenshot capture is not supported/.test(e)?we("execution_failed","unsupported_context","roblox_policy","no_retry",{validationStage:"preflight"}):/editableimage api is not enabled|allow mesh \/ image apis|allow http requests/.test(e)?we("execution_failed","feature_disabled","roblox_policy","no_retry",{validationStage:"preflight"}):/must be|invalid|cannot/.test(e)?we("execution_failed","validation","agent_request","fix_params",{validationStage:"plugin_handler"}):we("execution_failed","other","unknown","unknown")}function jl(t,e){if(t==="execute_luau"){let i=sge(e);if(i)return i}let n=rB(e);return t==="execute_luau"&&n.errorDetail==="runtime_error"&&/^\s*runtime error:/i.test(e)?we("execution_failed","runtime_error","agent_request","code_fix"):n}function iB(t){let n=(t instanceof Error?t.message:String(t)).toLowerCase();return/timeout/.test(n)?we("command_timeout","timeout","bridge","retry"):/econnrefused|socket hang up|network|econnreset|epipe/.test(n)?we("bridge_error","connection","bridge","wait_connection"):/eaddrinuse/.test(n)?we("bridge_error","port_in_use","bridge","no_retry"):we("exception","unexpected","server_exception","code_fix")}Vx();import{randomBytes as fge}from"node:crypto";var mge=["manage_ui_create_tree","manage_ui_update","manage_ui_delete"],pB=["manage_ui_preview","manage_ui_check"],gge=["game_genre","ui_role","style_family","layout_family","device_policy","safe_area_policy","existing_ui_strategy"];function iT(t){return t&&typeof t=="object"?t:void 0}function nT(t){return typeof t=="number"&&Number.isFinite(t)?t:0}function Wx(t){let e=iT(t);if(!e)return;let n={};for(let i of gge){let r=e[i];typeof r=="string"&&r.trim().length>0&&(n[i]=r)}return Object.keys(n).length>0?n:void 0}function rT(t){let e=Wx(t.qualityPlanSummary);if(e)return e;let n=iT(t.contextSummary),i=Wx(n?.qualityPlanSummary);if(i)return i;let r=Wx(n?.qualityPlan);if(r)return r;let a=Wx(n?.quality_plan);if(a)return a}function fB(t,e){return e?{...t??{},...e}:t}function hge(t){return typeof t=="string"?{snapshotId:t}:t&&typeof t=="object"?{snapshotId:typeof t.snapshotId=="string"?t.snapshotId:null,...t.designCheckSummary!==void 0&&{designCheckSummary:t.designCheckSummary},...t.capturedAt!==void 0&&{capturedAt:t.capturedAt}}:{snapshotId:null}}function mB(t,e,n,i,r){if(!e)return;let a=nT(e.priority_high),o=nT(e.priority_medium),s=nT(e.priority_low),c=typeof e.total=="number"&&Number.isFinite(e.total)?e.total:a+o+s,l=n??(typeof e.target=="string"?e.target:void 0);return{source:t,...l!==void 0&&{targetPath:l},...typeof i=="string"&&{snapshotId:i},...r!==void 0&&{capturedAt:r},priority_high:a,priority_medium:o,priority_low:s,total:c}}function gB(t,e){if(!e)return t;if(!t)return e;let n=t.targetPath===e.targetPath?t.targetPath:void 0,i=t.snapshotId===e.snapshotId?t.snapshotId:void 0;return{source:e.source,...n!==void 0&&{targetPath:n},...i!==void 0&&{snapshotId:i},...e.capturedAt!==void 0&&{capturedAt:e.capturedAt},priority_high:t.priority_high+e.priority_high,priority_medium:t.priority_medium+e.priority_medium,priority_low:t.priority_low+e.priority_low,total:t.total+e.total}}function yge(t){let e=iT(t);if(e)for(let n of["userMessage","intent","expectedBehavior"]){let i=e[n];if(typeof i=="string"&&i.trim().length>0)return i.trim().slice(0,80)}}function vge(){return{source:"unavailable",priority_high:0,priority_medium:0,priority_low:0,total:0}}function hB(t){let e=t.now??Date.now,n=null,i=null,r=u=>`${u}_${e()}_${fge(3).toString("hex")}`,a=()=>{i&&(clearTimeout(i),i=null)},o=()=>{a(),i=setTimeout(()=>{c("idle_timeout")},t.idleMs)},s=async u=>{try{return hge(await t.capturePreview(u))}catch{return{snapshotId:null}}},c=async u=>{if(!n)return;a();let d=n;n=null;let p={},f;for(let h of d.affectedPaths)if(d.afterSnapshotsPathPolicy[h]==="skip")p[h]=null;else{let v=await s(h);p[h]=v.snapshotId,f=gB(f,mB("after_snapshot",v.designCheckSummary,h,v.snapshotId,v.capturedAt))}let m=f??d.latestDesignCheckSummary??vge(),g={requestId:d.requestId,...d.contextId!==void 0&&{contextId:d.contextId},...d.label!==void 0&&{label:d.label},startedAt:d.startedAtIso,closedAt:new Date(e()).toISOString(),closeReason:u,ok:d.ok,affectedPaths:Array.from(d.affectedPaths).sort(),mutationCount:d.mutationCount,beforeSnapshots:d.beforeSnapshots,afterSnapshots:p,childMutationIds:d.childMutationIds,...d.qualityPlanSummary!==void 0&&{qualityPlanSummary:d.qualityPlanSummary},postChangeDesignCheckSummary:m};await lB(t.placeDir,g)},l=u=>({requestId:r("req"),contextId:u.contextId,label:yge(u.contextSummary),startedAtIso:new Date(e()).toISOString(),startedAtMs:e(),affectedPaths:new Set,beforeSnapshots:{},afterSnapshotsPathPolicy:{},childMutationIds:[],mutationCount:0,ok:!0,qualityPlanSummary:rT(u),latestDesignCheckSummary:void 0,pendingMutation:void 0});return{async beforeMutation(u){if(pB.includes(u.command)){if(n){let p=r("mut");n.qualityPlanSummary=fB(n.qualityPlanSummary,rT(u)),n.pendingMutation={mutationId:p,startedMs:e(),args:u}}return}if(!mge.includes(u.command))return;n&&n.contextId!==u.contextId?await c("context_change"):n&&a(),n||(n=l(u)),n.qualityPlanSummary=fB(n.qualityPlanSummary,rT(u)),u.targetPath&&!(u.targetPath in n.beforeSnapshots)&&(n.affectedPaths.add(u.targetPath),u.command==="manage_ui_create_tree"?n.beforeSnapshots[u.targetPath]=null:n.beforeSnapshots[u.targetPath]=(await s(u.targetPath)).snapshotId,u.command==="manage_ui_delete"?n.afterSnapshotsPathPolicy[u.targetPath]="skip":u.targetPath in n.afterSnapshotsPathPolicy||(n.afterSnapshotsPathPolicy[u.targetPath]="capture"));let d=r("mut");n.pendingMutation={mutationId:d,startedMs:e(),args:u}},async afterMutation(u){if(!n?.pendingMutation)return;let{mutationId:d,args:p}=n.pendingMutation,f={mutationId:d,requestId:n.requestId,ts:new Date(e()).toISOString(),command:p.command,origin:p.origin,...p.targetPath!==void 0&&{targetPath:p.targetPath},...p.briefId!==void 0&&{briefId:p.briefId},...u.diffSummary!==void 0&&{diffSummary:u.diffSummary},...u.changeDetails!==void 0&&{changeDetails:u.changeDetails},ok:u.ok,...u.error!==void 0&&{error:u.error},durationMs:u.durationMs};if(await uB(t.placeDir,f),n.pendingMutation=void 0,pB.includes(p.command)){n.latestDesignCheckSummary=gB(n.latestDesignCheckSummary,mB("check_results",u.designCheckSummary,p.targetPath,u.snapshotId,u.capturedAt));return}if(n.mutationCount++,n.childMutationIds.push(d),u.ok||(n.ok=!1),!n.contextId){await c("legacy_single");return}o()},async flushNow(){n&&await c("explicit")}}}var DB=100,Xge=12e4,Qge=15e3,NB=new Set(["manage_ui_create_tree","manage_ui_update","manage_ui_delete"]);function ehe(t,e){return`License required for internal command ${t}. ${e??"Activate Pro license to use this feature."}`}var the={Text:{category:"text",label:"\uD14D\uC2A4\uD2B8"},PlaceholderText:{category:"text",label:"\uD50C\uB808\uC774\uC2A4\uD640\uB354"},TextColor3:{category:"color",label:"\uAE00\uC790\uC0C9"},BackgroundColor3:{category:"color",label:"\uBC30\uACBD\uC0C9"},BorderColor3:{category:"color",label:"\uD14C\uB450\uB9AC\uC0C9"},ImageColor3:{category:"color",label:"\uC774\uBBF8\uC9C0\uC0C9"},Size:{category:"size",label:"\uC0AC\uC774\uC988"},TextSize:{category:"size",label:"\uAE00\uC790 \uD06C\uAE30"},Position:{category:"layout",label:"\uC704\uCE58"},AnchorPoint:{category:"layout",label:"\uC575\uCEE4"},Rotation:{category:"layout",label:"\uD68C\uC804"},LayoutOrder:{category:"layout",label:"\uB808\uC774\uC544\uC6C3 \uC21C\uC11C"},Visible:{category:"state",label:"\uD45C\uC2DC \uC0C1\uD0DC"},Active:{category:"state",label:"\uD65C\uC131 \uC0C1\uD0DC"},Interactable:{category:"state",label:"\uC0C1\uD638\uC791\uC6A9 \uC0C1\uD0DC"},Selectable:{category:"state",label:"\uC120\uD0DD \uAC00\uB2A5"},Enabled:{category:"state",label:"\uD65C\uC131\uD654"},Image:{category:"asset",label:"\uC774\uBBF8\uC9C0"},Texture:{category:"asset",label:"\uD14D\uC2A4\uCC98"},SoundId:{category:"asset",label:"\uC0AC\uC6B4\uB4DC"}},nhe={text:"\uD14D\uC2A4\uD2B8",color:"\uCEEC\uB7EC",size:"\uC0AC\uC774\uC988",layout:"\uB808\uC774\uC544\uC6C3",state:"\uC0C1\uD0DC",asset:"\uC5D0\uC14B",property:"\uC18D\uC131"},rhe=Object.entries(Tl).reduce((t,[e,n])=>{for(let i of n.validActions)t[`${e}_${i}`]=e;return t},{});function RB(t){return{toolName:rhe[t]||t,commandName:t}}function EB(t,e){if(typeof t.contextId=="string"||!e||typeof e!="object")return t;let n=e.contextId;return typeof n=="string"?{...t,contextId:n}:t}function Gx(t,e){if(t!=="manage_sync_status_current_place")return e;let{placeId:n,...i}=e;return i}function ihe(t,e){let n=e.routing;return{requestId:t,success:!1,error:e.message,errorCode:e.code,routing:n,data:{routing:n}}}async function ahe(t,e){let n=t.syncController;if(!n)return null;try{let i=e.placeId,r=n.getDefaultRuntimePlaceId(),a=null;if(typeof i=="number"&&Number.isFinite(i))a=i;else if(typeof i=="string"&&i.trim().length>0){let s=Number.parseInt(i,10);Number.isFinite(s)&&(a=s)}if(a===null&&(a=r),a===null||!Number.isFinite(a))return null;let o=a===r?n.getDefaultRuntimePlaceName():null;return typeof o=="string"&&o.length>0?await n.config.resolvePlaceRoot(a,o):n.config.getPlaceRoot(a)}catch{return null}}function ohe(t){let e=t.tree;if(!e||typeof e!="object")return;let n=e,i=typeof n.name=="string"&&n.name.length>0?n.name:void 0;return i?`${typeof n.parent=="string"&&n.parent.length>0?n.parent:"StarterGui"}.${i}`:void 0}function she(t,e){let n=e.targetPath;if(typeof n=="string"&&n.length>0)return n;if(t==="manage_ui_create_tree")return ohe(e)}function che(t){let e=the[t];if(e)return e;let n=t.toLowerCase();return n.includes("color")?{category:"color",label:"\uC0C9\uC0C1"}:t==="Size"||n.endsWith("size")||n.includes("scale")?{category:"size",label:"\uC0AC\uC774\uC988"}:n.includes("position")||n.includes("anchor")||n.includes("rotation")||n.includes("layout")?{category:"layout",label:"\uB808\uC774\uC544\uC6C3"}:n.includes("visible")||n.includes("active")||n.includes("enabled")||n.includes("selectable")||n.includes("interactable")?{category:"state",label:"\uC0C1\uD0DC"}:n.includes("image")||n.includes("texture")||n.includes("sound")||n.includes("asset")?{category:"asset",label:"\uC5D0\uC14B"}:n.includes("text")||n.includes("placeholder")?{category:"text",label:"\uD14D\uC2A4\uD2B8"}:{category:"property",label:t}}function TB(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function lhe(t){if(!t||typeof t!="object")return new Map;let e=t,n=e.changed_properties??e.changedProperties;if(!Array.isArray(n))return new Map;let i=new Map;for(let r of n){if(!r||typeof r!="object")continue;let a=r,o=a.property;if(typeof o!="string"||o.length===0)continue;let s=TB(a,"before"),c=TB(a,"after");i.set(o,{...s&&{before:a.before},...c&&{after:a.after},hasBefore:s,hasAfter:c})}return i}function jB(t,e){let i=t.changes?.properties;if(!i||typeof i!="object")return;let r=lhe(e),a=Object.entries(i).map(([o,s])=>{let c=che(o),l=r.get(o),u={property:o,category:c.category,label:c.label,after:l?.hasAfter?l.after:s};return l?.hasBefore&&(u.before=l.before),u});return a.length>0?a:void 0}function MB(t){if(!t||t.length===0)return;let e=new Map;for(let r of t)e.set(r.category,(e.get(r.category)??0)+1);let i=["text","color","size","layout","state","asset","property"].map(r=>{let a=e.get(r)??0;return a>0?`${nhe[r]} ${a}\uAC1C`:null}).filter(r=>r!==null);return i.length>0?`${i.join(", ")} \uBCC0\uACBD`:void 0}function AB(t,e){if(t==="manage_ui_update"){let n=e.changes,i=MB(jB(e));if(i)return i;let r=n?.properties?Object.keys(n.properties).length:0,a=Array.isArray(n?.addChildren)?n.addChildren.length:0,o=Array.isArray(n?.removeChildren)?n.removeChildren.length:0;return`${r} props, +${a}, -${o}`}if(t==="manage_ui_create_tree")return"tree \uC0DD\uC131";if(t==="manage_ui_delete")return"\uC81C\uAC70\uB428"}function Af(t){return t&&typeof t=="object"?t:void 0}function Kx(t,e){let n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:0}function zB(t){let e=Af(t),n=Af(e?.design_check_summary);if(n)return{priority_high:Kx(n,"priority_high"),priority_medium:Kx(n,"priority_medium"),priority_low:Kx(n,"priority_low"),total:Kx(n,"total"),...typeof n.scope=="string"&&{scope:n.scope},...typeof n.target=="string"&&{target:n.target}}}function LB(t){let n=Af(t)?.snapshot_id;return typeof n=="string"?n:null}function $B(t){if(typeof t=="string"&&t.trim().length>0)return t;if(typeof t=="number"&&Number.isFinite(t)){let e=t<1e10?t*1e3:t;return new Date(e).toISOString()}}function UB(t){let e=Af(t),n=Af(e?.meta);return $B(n?.captured_at)??$B(n?.evaluated_at)}function uhe(t,e){let n=t.uiStudioRecorders.get(e);if(n)return n;let i=hB({placeDir:e,idleMs:Qge,capturePreview:async r=>{try{let a=await ir(t,"manage_ui_preview",{targetPath:r},Yx());if(!a.success||!a.data||typeof a.data!="object")return null;let o=zB(a.data),s=UB(a.data);return{snapshotId:LB(a.data),...o!==void 0&&{designCheckSummary:o},...s!==void 0&&{capturedAt:s}}}catch{return null}}});return t.uiStudioRecorders.set(e,i),i}async function dhe(t,e,n){if(!NB.has(e))return null;let i=await ahe(t,n);if(!i)return null;let r=uhe(t,i),a=e,o=typeof n.contextId=="string"?n.contextId:void 0,s=n.contextSummary,c=s!==void 0&&typeof s=="object"?s:void 0,l=she(a,n),u=typeof n.briefId=="string"?n.briefId:void 0,d={command:a,...o!==void 0&&{contextId:o},...c!==void 0&&{contextSummary:c},...l!==void 0&&{targetPath:l},...u!==void 0&&{briefId:u},origin:n.__origin==="dashboard"?"dashboard":"ai"};try{return await r.beforeMutation(d),{recorder:r,command:a,params:n,startedAt:Date.now()}}catch(p){return y.debug("UI Studio recorder beforeMutation \uC2E4\uD328 (\uBB34\uC2DC)",{error:p}),null}}async function OB(t,e){if(t)try{let n=t.command==="manage_ui_update"?jB(t.params,e.data):void 0,i=t.command==="manage_ui_update"?MB(n)??AB(t.command,t.params):AB(t.command,t.params),r=zB(e.data),a=LB(e.data),o=UB(e.data);await t.recorder.afterMutation({ok:e.success,durationMs:Date.now()-t.startedAt,...i!==void 0&&{diffSummary:i},...n!==void 0&&{changeDetails:n},...e.error!==void 0&&{error:e.error},...r!==void 0&&{designCheckSummary:r},...a!==null&&{snapshotId:a},...o!==void 0&&{capturedAt:o}})}catch(n){y.debug("UI Studio recorder afterMutation \uC2E4\uD328 (\uBB34\uC2DC)",{error:n})}}async function Jx(t,e,n,i,r,a){if(!t.historyManager)return;let o=!r.success&&r.error?jl(n,r.error):void 0,s=Nl({resultSuccess:r.success,resultData:r.data,resultError:r.error,tier:zn(n),...o?{failureClassification:o}:{}});if(r.success){let u=s.kind==="success_fallback"&&r.data&&typeof r.data=="object"?{...r.data,outcomeStatus:"fallback",requestedCommand:n,executedCommand:s.fallbackCommand,...s.alternatives?{alternatives:s.alternatives}:{}}:r.data,d=Gx(n,i);r.routing?await t.historyManager.recordSuccess(e,d,u,a,n,void 0,r.routing):await t.historyManager.recordSuccess(e,d,u,a,n);return}if(s.kind==="blocked_unsupported"){await t.historyManager.recordBlockedOutcome(e,Gx(n,i),r.error||"Pro action blocked in Basic mode","blocked_unsupported",{executionTimeMs:a,command:n,...r.routing?{routing:r.routing}:{}});return}if(s.kind==="blocked_fallback_failed"){await t.historyManager.recordBlockedOutcome(e,Gx(n,i),r.error||"Pro action blocked in Basic mode","blocked_fallback_failed",{executionTimeMs:a,command:n,...s.fallbackCommand?{fallbackCommand:s.fallbackCommand}:{},...s.blockedDetail?{blockedDetail:s.blockedDetail}:{},...r.routing?{routing:r.routing}:{}});return}let c=s.kind==="warning"?t.historyManager.recordWarning.bind(t.historyManager):t.historyManager.recordFailure.bind(t.historyManager),l=Gx(n,i);r.routing?await c(e,l,r.error||"Unknown error",a,r.errorCode??o?.errorType.toUpperCase(),n,void 0,r.routing):await c(e,l,r.error||"Unknown error",a,r.errorCode??o?.errorType.toUpperCase(),n)}function cT(t,e,n){let i=t.pendingCommands.get(e)||[];i.length>=DB&&i.shift(),i.push(n),t.pendingCommands.set(e,i)}function phe(t,e){t.globalPendingCommands.length>=DB&&t.globalPendingCommands.shift(),t.globalPendingCommands.push(e)}function FB(t,e,n){let i=Yx(),r={requestId:i,command:e.command,params:e.params,timestamp:Date.now(),queueTimeoutMs:e.queueTimeoutMs,ackedTimeoutMs:e.ackedTimeoutMs,state:vn.QUEUED,targetClientId:n,resolve:()=>{},reject:a=>{y.debug("Auxiliary playtest stop command ended without awaited response",{requestId:i,targetClientId:n,error:a.message})},timeoutId:null};return t.commandQueue.set(i,r),r.timeoutId=setTimeout(()=>{Jb(t,r,r.queueTimeoutMs)},r.queueTimeoutMs),{event:"command",id:i,data:{command:r.command,requestId:i,params:r.params}}}function fhe(t,e,n,i){if(!gf(e.data.command))return;let r=t.commandQueue.get(e.data.requestId);if(!r)return;qB(t,r);let a=n.filter(o=>o.clientId!==i);for(let o of a){let s=FB(t,r,o.clientId);cT(t,o.clientId,s)}a.length>0&&y.info("Fan-out playtest stop command to active plugin clients",{requestId:e.data.requestId,primaryClientId:i,auxiliaryClientIds:a.map(o=>o.clientId)})}function qB(t,e,n){for(let i of gq)setTimeout(()=>{let a=n?[...new Set(n)]:[...new Set(Cn(t).map(o=>o.clientId))];for(let o of a){if(!t.pluginClients.get(o))continue;let c=FB(t,e,o);cT(t,o,c)}y.info("Retry playtest stop command to active plugin clients",{sourceRequestId:e.requestId,delayMs:i,targetClientIds:a}),hl(t)},i).unref?.()}function BB(t){return t==="clientId"||t==="targetAlias"||t==="placeId"}function mhe(t,e,n){if(!n||!gf(e.data.command))return!1;let i=t.commandQueue.get(e.data.requestId)?.routing?.selectionMode;return!BB(i)}function ghe(t,e,n){y.debug("Broadcasting command",{command:e.data.command,requestId:e.data.requestId,targetClientId:n||"all",activeWebsocketClients:Cn(t).length});let i=n;if(n){cT(t,n,e);let r=t.commandQueue.get(e.data.requestId),a=r?.routing?.selectionMode;if(r&&gf(e.data.command)&&BB(a))qB(t,r,[n]);else if(mhe(t,e,n)){let o=Cn(t).sort((s,c)=>c.lastSeen-s.lastSeen);fhe(t,e,o,n),i=void 0}}else phe(t,e);hl(t,i)}async function HB(t,e,n){let i=Date.now(),r="",a={};try{let o=e.body;r=o.command??"",a=o.params||{};let s=o.requestId;if(o.instanceId||(t.serverLastCommandAt=Date.now()),o.instanceId){let m=t.mcpInstances.get(o.instanceId);m&&(m.lastCommandAt=Date.now(),m.lastSeen=m.lastCommandAt)}let c=RB(r),l=typeof o.timeout=="number"&&Number.isFinite(o.timeout)&&o.timeout>0?{timeout:o.timeout}:void 0,u=o.instanceId?t.mcpInstances.get(o.instanceId)?.sessionId??t.sessionId:t.sessionId;if(!r){n.status(400).json({error:"Missing command"});return}if(y.debug("Received execute request",{command:r,requestId:s}),r==="manage_camera_play_screenshot"){let m="manage_camera.play_screenshot is not supported. Screenshot capture is available only in Edit mode via manage_camera.screenshot.",g=Date.now()-i;t.historyManager&&await t.historyManager.recordFailure("manage_camera",a,m,g,"UNSUPPORTED_COMMAND",r),n.json({requestId:s,success:!1,error:m});return}if(r==="get_cached_selection"){let m=a.maxAge,g=mf(t,m!==void 0?m:3e4),h=Date.now()-i;if(!g){let _={requestId:s,success:!0,data:{cached:!1,message:"No cached selection data available. The plugin may not be connected or no selection changes have occurred yet."}};t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,_.data,h,c.commandName),n.json(_);return}let v=Date.now()-g.timestamp,x={cached:!0,selection:g.selection,count:g.count,timestamp:g.timestamp,age:v};t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,x,h,c.commandName),n.json({requestId:s,success:!0,data:x});return}if(r==="get_connection_info"){let m=await Dx(t),g=Date.now()-i;t.historyManager&&await t.historyManager.recordSuccess(c.toolName,a,m,g,c.commandName),n.json({requestId:s,success:!0,data:m});return}if(jx(r)==="internal"){if(!t.internalCommandExecutor){n.status(503).json({requestId:s,success:!1,error:`Internal command executor is not initialized for command: ${r}`});return}if(zn(r)==="pro"){if(!t.licenseState){n.status(503).json({requestId:s,success:!1,error:`License state manager is not initialized for internal command: ${r}`});return}let x=await t.licenseState.evaluateProAccess();if(!x.allowed){let _=ehe(r,x.reason),I=Date.now()-i;t.historyManager&&await Jx(t,c.toolName,c.commandName,a,{success:!1,error:_},I),n.json({requestId:s,success:!1,error:_});return}}let m={...a,__sessionId:u},g=await t.internalCommandExecutor(r,m),h=Date.now()-i,v=EB(m,g.data);t.historyManager&&await Jx(t,c.toolName,c.commandName,v,{success:g.success,data:g.data,error:g.error||"Internal command failed"},h),n.json({requestId:s,...g});return}let d=await ir(t,r,a,s,l),p=Date.now()-i,f={...EB(a,d.data),__sessionId:u};t.historyManager&&await Jx(t,c.toolName,c.commandName,f,d,p),n.json(d)}catch(o){let s=Date.now()-i,c=Mn(o);if(t.historyManager&&r){let l=RB(r);await t.historyManager.recordFailure(l.toolName,a,c,s,"EXCEPTION",l.commandName)}y.error("Execute request failed",o),n.status(500).json({success:!1,error:c})}}async function ZB(t,e,n){let i=Date.now(),r=e.body,a=r.action;if(!a||typeof a!="string"){n.status(400).json({success:!1,error:"Missing required field: action"});return}if(!new Set(["get","set","get_all","set_multiple","get_attr","set_attr","get_all_attrs","delete_attr","add_tag","remove_tag","check_tag","get_tags","get_tagged"]).has(a)){n.status(400).json({success:!1,error:`Unsupported action: ${a}`});return}let s=`manage_properties_${a}`,c=Yx(),{action:l,...u}=r;try{t.serverLastCommandAt=Date.now();let d=await ir(t,s,u,c),p=Date.now()-i;t.historyManager&&await Jx(t,"manage_properties",s,u,d,p),n.json(d)}catch(d){let p=Date.now()-i,f=Mn(d);t.historyManager&&await t.historyManager.recordFailure("manage_properties",u,f,p,"EXCEPTION",s),y.error("/api/properties \uC694\uCCAD \uCC98\uB9AC \uC2E4\uD328",d),n.status(500).json({success:!1,error:f})}}async function ir(t,e,n,i,r){if(y.debug("Executing command locally",{command:e,requestId:i}),Q6(t,i)){let d=`Duplicate requestId '${i}' for command '${e}'. Generate a unique requestId for each command.`;return y.warn("Duplicate execute request rejected",{command:e,requestId:i}),{requestId:i,success:!1,error:d}}let a;try{a=Nx(t,Cn(t),n,e)}catch(d){if(d instanceof on)return y.warn("Command target selection failed",{command:e,requestId:i,errorCode:d.code,routing:d.routing}),ihe(i,d);throw d}let o=NB.has(e)?await dhe(t,e,n):null,s=t.config.requestTimeout,c=r?.timeout??Math.max(t.config.requestTimeout,Xge),l=KE.has(e)?await eB({ctx:t,command:e,params:n}):n,u=new Promise((d,p)=>{let f=Date.now(),m={requestId:i,command:e,params:l,timestamp:f,queueTimeoutMs:s,ackedTimeoutMs:c,state:vn.QUEUED,...a.targetClientId?{targetClientId:a.targetClientId}:{},routing:a.routing,resolve:d,reject:p,timeoutId:null};t.commandQueue.set(i,m),Zb(t,a.targetClientId,f),m.timeoutId=setTimeout(()=>{Jb(t,m,s)},s)});return ghe(t,{event:"command",id:Yx(),data:{command:e,requestId:i,params:l}},a.targetClientId),u.then(async d=>{let p=d;if(e==="manage_ui_preview"&&d.success&&d.data)try{let{processPreviewResult:f,resolvePreviewPlaceDirFromCtx:m}=await Promise.resolve().then(()=>(sT(),oT)),g=await m(t,n),h=await f("manage_ui_preview",d.data,g);p={...d,data:h.data,...h.mcpContent?{mcpContent:h.mcpContent}:{}}}catch(f){y.warn("preview post-processing failed",{error:f instanceof Error?f.message:String(f)})}if(e==="manage_ui_check"&&d.success&&d.data&&n.includeVisualAnalysis===!0)try{let{resolvePreviewPlaceDirFromCtx:f}=await Promise.resolve().then(()=>(sT(),oT)),{processCheckResult:m}=await Promise.resolve().then(()=>(PB(),kB)),g=await f(t,n),h=await m("manage_ui_check",d.data,g,n);p={...p,data:h.data}}catch(f){y.warn("check visual post-processing failed",{error:f instanceof Error?f.message:String(f)})}return JE.has(e)?p=await tB({ctx:t,command:e,params:n,result:p}):e===GE&&(p=await nB({ctx:t,params:n,result:p})),p}).then(async d=>(await OB(o,{success:d.success,...d.data!==void 0&&{data:d.data},...d.error!==void 0&&{error:d.error}}),d),async d=>{throw await OB(o,{success:!1,error:Mn(d)}),d})}ce();wi();function Xx(t,e){let n={};e.provider!==void 0&&(n.provider=e.provider),e.tier!==void 0&&(n.tier=e.tier),e.status!==void 0&&(n.status=e.status),e.canUsePro!==void 0&&(n.canUsePro=e.canUsePro),e.cleared===!0&&(n.cleared=!0),rt(t,"license",n)}function ti(t,e,n,i){t.status(e).json({success:!1,error:{code:n,message:i}})}function hhe(t){if(typeof t!="string")return;let e=t.trim().toLowerCase();return e.length>0?e:void 0}function Qx(t,e){if(e==="plugin")return t;let n={...t};return delete n.sessionToken,n}function $f(t,e,n,i){let r=hhe(i??e.query.provider)??"auto";return t.licenseState?.supportsProvider(r)===!1?(ti(n,400,"LICENSE_PROVIDER_UNSUPPORTED",`provider "${r}" is not supported`),null):r}function Of(t,e){return t.licenseState?!0:(ti(e,503,"LICENSE_NOT_INITIALIZED","License system is not initialized"),!1)}function yhe(t){if(!t||typeof t!="object")return!1;let e=t;return(e.canUsePro===!0||e.canUsePro===!1)&&typeof e.status=="string"&&typeof e.checkedAt=="number"}function Df(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=typeof r?.licenseKey=="string"?r.licenseKey:"";if(!a.trim()){ti(n,400,"LICENSE_KEY_REQUIRED","licenseKey is required");return}let o=$f(t,e,n,r?.provider);if(!o)return;let s=typeof r?.pluginClientId=="string"?r.pluginClientId:typeof e.query.clientId=="string"?e.query.clientId:void 0,c=typeof r?.deviceId=="string"?r.deviceId:void 0,l={licenseKey:a,provider:o,clientType:i};s&&(l.pluginClientId=s),c&&(l.deviceId=c),t.licenseState.activateGateway(l).then(u=>{t.analyticsManager?.setTier(u.canUsePro?"pro":"basic"),Xx(t,{provider:u.provider,tier:u.canUsePro?"pro":"basic",status:u.status,canUsePro:u.canUsePro}),n.json(Qx(u,i))}).catch(u=>{y.warn("License activate failed",{error:u instanceof Error?u.message:"unknown_error"}),ti(n,502,"LICENSE_ACTIVATE_FAILED",u instanceof Error?u.message:"License activation failed")})}function Nf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=$f(t,e,n);if(r)try{let a=t.licenseState.getStatus(r);t.analyticsManager?.setTier(a.canUsePro?"pro":"basic"),n.json(Qx(a,i))}catch(a){y.warn("License status check failed",{error:a instanceof Error?a.message:"unknown_error"}),ti(n,502,"LICENSE_STATUS_FAILED",a instanceof Error?a.message:"License status check failed")}}function jf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=$f(t,e,n,r?.provider);if(!a)return;let o={provider:a,clientType:i};i==="plugin"&&typeof r?.sessionToken=="string"&&r.sessionToken.trim()&&(o.sessionToken=r.sessionToken.trim()),typeof r?.pluginClientId=="string"&&(o.pluginClientId=r.pluginClientId),typeof r?.deviceId=="string"&&(o.deviceId=r.deviceId),t.licenseState.refreshGateway(o).then(s=>{t.analyticsManager?.setTier(s.canUsePro?"pro":"basic"),Xx(t,{provider:s.provider,tier:s.canUsePro?"pro":"basic",status:s.status,canUsePro:s.canUsePro}),n.json(Qx(s,i))}).catch(s=>{y.warn("License refresh failed",{error:s instanceof Error?s.message:"unknown_error"}),ti(n,502,"LICENSE_REFRESH_FAILED",s instanceof Error?s.message:"License refresh failed")})}function Mf(t,e,n,i="plugin"){if(!Of(t,n))return;let r=e.body,a=$f(t,e,n,r?.provider);a&&t.licenseState.resetGateway({provider:a,clientType:i}).then(o=>{t.analyticsManager?.setTier("basic"),Xx(t,{provider:o.provider,tier:"basic",status:o.status,canUsePro:o.canUsePro,cleared:!0}),n.json(Qx(o,i))}).catch(o=>{y.warn("License reset failed",{error:o instanceof Error?o.message:"unknown_error"}),ti(n,502,"LICENSE_RESET_FAILED",o instanceof Error?o.message:"License reset failed")})}function lT(t,e,n){if(!Of(t,n))return;let i=e.body,r=$f(t,e,n,i?.provider);if(!r)return;if(i?.clientType!=="plugin"){ti(n,400,"LICENSE_CLIENT_TYPE_INVALID","clientType must be plugin");return}let a=typeof i?.sessionToken=="string"&&i.sessionToken.trim()?i.sessionToken.trim():void 0,o=yhe(i?.snapshot)?i.snapshot:void 0;if(!o&&!a){ti(n,400,"LICENSE_BOOTSTRAP_REQUIRED","snapshot or sessionToken is required");return}let s={provider:r,clientType:"plugin"};o&&(s.snapshot=o),a&&(s.sessionToken=a),t.licenseState.bootstrap(s).then(c=>{t.analyticsManager?.setTier(c.canUsePro?"pro":"basic"),Xx(t,{provider:c.provider,tier:c.canUsePro?"pro":"basic",status:c.status,canUsePro:c.canUsePro}),n.json({ok:!0})}).catch(c=>{y.warn("License bootstrap failed",{error:c instanceof Error?c.message:"unknown_error"}),ti(n,502,"LICENSE_BOOTSTRAP_FAILED",c instanceof Error?c.message:"License bootstrap failed")})}function VB(t){t.app.post("/license/bootstrap",(e,n)=>lT(t,e,n)),t.app.post("/license/activate",(e,n)=>Df(t,e,n,"plugin")),t.app.post("/license/refresh",(e,n)=>jf(t,e,n,"plugin")),t.app.post("/license/reset",(e,n)=>Mf(t,e,n,"plugin")),t.app.get("/license/status",(e,n)=>Nf(t,e,n,"plugin"))}ft();ce();import{promises as e_}from"fs";import uT from"path";function vhe(t){let e=t.config.appDataDir??ot();return uT.join(e,"observability","logs")}async function Fl(t,e,n){let i=e.query.clientId;if(i&&t.pluginClients.has(i)){let r=t.pluginClients.get(i);r.lastSeen=Date.now()}try{let r=e.body;if(!r||!Array.isArray(r.logs)){y.warn("Invalid logs request",{body:r}),n.status(400).json({error:"Invalid request body"});return}let a=vhe(t);await e_.mkdir(a,{recursive:!0});let c=`plugin-${new Date().toISOString().split("T")[0]}.log`,l=uT.join(a,c),u=uT.join(a,"current.log"),d=r.logs.map(p=>`[${new Date(p.timestamp*1e3).toISOString().replace("T"," ").substring(0,19)}] [${p.level}] ${p.message}`).join(`
505
505
  `)+`
506
506
  `;await e_.appendFile(l,d,"utf-8");try{let p="";try{p=await e_.readFile(u,"utf-8")}catch{}let m=(p+d).split(`
507
507
  `).slice(-500).join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weppy/roblox-mcp",
3
- "version": "2.10.1",
3
+ "version": "2.10.2",
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": "dist/index.js",
6
6
  "type": "module",
Binary file