@weppy/roblox-mcp 2.10.0 → 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.
Files changed (34) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +8 -2
  3. package/dashboard/dist/assets/{AssetsPage-D9X2pUea.js → AssetsPage-DFC---br.js} +1 -1
  4. package/dashboard/dist/assets/{ChangelogDetailPage-Bc77mNht.js → ChangelogDetailPage-gvZDaLft.js} +1 -1
  5. package/dashboard/dist/assets/{ChangelogPage-Cvy3ismU.js → ChangelogPage-eOFIHxbD.js} +1 -1
  6. package/dashboard/dist/assets/{ConfirmModal-CEmy8izm.js → ConfirmModal-BqCEvp7Y.js} +1 -1
  7. package/dashboard/dist/assets/ConnectionPage-Ca5WLCm3.css +1 -0
  8. package/dashboard/dist/assets/ConnectionPage-DAz-lhiE.js +11 -0
  9. package/dashboard/dist/assets/{ControlsPage-CkTB6mEk.js → ControlsPage-CKEswTa6.js} +1 -1
  10. package/dashboard/dist/assets/{CurrentPlaceScope-CuZXV9Ku.js → CurrentPlaceScope-C8U9I15o.js} +1 -1
  11. package/dashboard/dist/assets/{GameChangeDetail-D2QTkbEB.js → GameChangeDetail-CMSmIwO-.js} +1 -1
  12. package/dashboard/dist/assets/{InfoLabel-BUXacsTE.js → InfoLabel-BAhsgLcj.js} +1 -1
  13. package/dashboard/dist/assets/{OverviewPage-CX5zVj8P.js → OverviewPage-COMQ7wYS.js} +1 -1
  14. package/dashboard/dist/assets/{PageHeader-B0qiATU4.js → PageHeader-Bfy2f-GH.js} +1 -1
  15. package/dashboard/dist/assets/{PlaytestPage-folHMgTW.js → PlaytestPage-BIkP1kCO.js} +1 -1
  16. package/dashboard/dist/assets/{SettingsPage-nlNo4CBL.js → SettingsPage-ClSPo4J8.js} +1 -1
  17. package/dashboard/dist/assets/{StatusBadge-B2VLfqa6.js → StatusBadge-Df9BQsJU.js} +1 -1
  18. package/dashboard/dist/assets/{SyncPage-Bi8xaHnB.js → SyncPage-O1vlpViJ.js} +1 -1
  19. package/dashboard/dist/assets/{Tabs-DqGYr78-.js → Tabs-Ccrw7Hjb.js} +1 -1
  20. package/dashboard/dist/assets/{ToolsPage-DVYql6ES.js → ToolsPage-CdPa3eYv.js} +1 -1
  21. package/dashboard/dist/assets/{TooltipText-DaLR7eg1.js → TooltipText-CGH7dKN6.js} +1 -1
  22. package/dashboard/dist/assets/{UiStudioPage-CHzKSJCc.js → UiStudioPage-io4UBG0Y.js} +1 -1
  23. package/dashboard/dist/assets/{WhatsNewPage-D5LMzwyf.js → WhatsNewPage-CGKwvik4.js} +1 -1
  24. package/dashboard/dist/assets/{copy-0T6g5IWT.js → copy-D-nSZB9j.js} +1 -1
  25. package/dashboard/dist/assets/{index-BDJHcdyQ.js → index-CnXGGM07.js} +13 -13
  26. package/dashboard/dist/assets/{sample-requests-Fif4AVnz.js → sample-requests-ythz0BoY.js} +1 -1
  27. package/dashboard/dist/assets/{useLiveUptime-KCA8LzCI.js → useLiveUptime-1Et9Q6mq.js} +1 -1
  28. package/dashboard/dist/assets/{useSettings-BJSPSJ0b.js → useSettings-DKMlodE_.js} +1 -1
  29. package/dashboard/dist/index.html +1 -1
  30. package/dist/index.js +78 -78
  31. package/package.json +1 -1
  32. package/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
  33. package/dashboard/dist/assets/ConnectionPage-B5daijue.css +0 -1
  34. package/dashboard/dist/assets/ConnectionPage-C_XNqIG-.js +0 -11
package/CHANGELOG.md CHANGED
@@ -15,6 +15,26 @@ All notable changes to this project will be documented in this file.
15
15
 
16
16
 
17
17
 
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
+
32
+ ## [2.10.1] - 2026-07-04
33
+
34
+ ### Bug Fixes
35
+
36
+ - **Improved Test and Run state detection in Roblox Studio** — The Dashboard now reports Studio targets as Running or Paused more accurately when you start Test or Run from Roblox Studio, pause the simulation, or let WEPPY start a playtest. This makes it easier to tell whether an AI agent is working against Edit mode, an active playtest, or a paused simulation without changing your setup.
37
+
18
38
  ## [2.10.0] - 2026-07-03
19
39
 
20
40
  ### Features
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 |
@@ -1,4 +1,4 @@
1
- import{i as ne,a as $,n as ve,u as me,j as t,P as pt,I as mt,r as c,o as ht,R as Ze,X as Ue,E as xt,p as Je,g as gt,e as bt,h as ft}from"./index-BDJHcdyQ.js";import{C as Qe}from"./ConfirmModal-CEmy8izm.js";import{B as Ee,C as yt,D as Te,P as jt}from"./PageHeader-B0qiATU4.js";import{T as G}from"./TooltipText-DaLR7eg1.js";import{C as et}from"./copy-0T6g5IWT.js";import"./ConfirmModal.module-D1aZY2bQ.js";/**
1
+ import{i as ne,a as $,n as ve,u as me,j as t,P as pt,I as mt,r as c,o as ht,R as Ze,X as Ue,E as xt,p as Je,g as gt,e as bt,h as ft}from"./index-CnXGGM07.js";import{C as Qe}from"./ConfirmModal-BqCEvp7Y.js";import{B as Ee,C as yt,D as Te,P as jt}from"./PageHeader-Bfy2f-GH.js";import{T as G}from"./TooltipText-CGH7dKN6.js";import{C as et}from"./copy-D-nSZB9j.js";import"./ConfirmModal.module-D1aZY2bQ.js";/**
2
2
  * @license lucide-react v1.8.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{r,a as w,u as V,b as G,c as D,d as F,j as e}from"./index-BDJHcdyQ.js";import{I as P}from"./InfoLabel-BUXacsTE.js";import{G as U}from"./GameChangeDetail-D2QTkbEB.js";import{T as g}from"./TooltipText-DaLR7eg1.js";function H(t){const i={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const o of t)switch(o.category){case"script":o.changeType==="create"?i.scriptsCreated++:i.scriptsModified++;break;case"instance":o.changeType==="create"?i.instancesCreated++:o.changeType==="delete"?i.instancesDeleted++:o.changeType==="move"&&i.instancesMoved++;break;case"property":i.propertiesChanged++;break;case"lighting":i.lightingChanged=!0;break;case"terrain":i.terrainChanged=!0;break;case"asset":i.assetsInserted++;break}return i}function W(t){if(typeof t=="number")return{placeId:String(t)}}function Y(t,i){const[o,h]=r.useState(""),[I,a]=r.useState(""),[d,x]=r.useState(),[E,L]=r.useState("completed"),[f,$]=r.useState([]),[O,R]=r.useState([]),[A,p]=r.useState([]),[_,j]=r.useState(),[b,v]=r.useState(),[S,C]=r.useState(),[N,T]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[k,u]=r.useState(!0),[q,y]=r.useState(null),m=r.useCallback(async()=>{if(t){u(!0),y(null);try{const s=W(i),[c,l]=await Promise.all([s?w.get(`/api/dashboard/changelog/${t}`,s):w.get(`/api/dashboard/changelog/${t}`),s?w.get(`/api/dashboard/changelog/${t}/changes`,s):w.get(`/api/dashboard/changelog/${t}/changes`)]);h(c.entryId),a(c.startTime),x(c.endTime),L(c.status),$(c.entries),R(c.failures),j(c.contextSummary),v(c.replayMetadata),C(c.verificationSummary),p(l.changes),T(H(l.changes))}catch(s){y(s instanceof Error?s.message:"Failed to load changelog detail")}finally{u(!1)}}},[t,i]);return r.useEffect(()=>{m()},[m]),{entryId:o,startTime:I,endTime:d,status:E,entries:f,failures:O,changes:A,changeSummary:N,contextSummary:_,replayMetadata:b,verificationSummary:S,loading:k,error:q,refresh:m}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function J(t){return z[t]??"❓"}const Q="_page_q2jbi_2",X="_header_q2jbi_10",Z="_backLink_q2jbi_16",ee="_headerTitle_q2jbi_29",te="_headerTime_q2jbi_37",ne="_statusActive_q2jbi_44",ae="_statusCompleted_q2jbi_49",se="_section_q2jbi_54",ie="_sectionTitle_q2jbi_61",ce="_summaryGrid_q2jbi_74",re="_summaryCard_q2jbi_80",oe="_summaryCardActive_q2jbi_94",le="_summaryIcon_q2jbi_99",de="_summaryCount_q2jbi_105",me="_summaryLabel_q2jbi_112",ge="_contextGrid_q2jbi_121",he="_contextRow_q2jbi_127",ue="_contextKey_q2jbi_133",ye="_contextValue_q2jbi_141",xe="_timelineFilter_q2jbi_149",fe="_filterLabel_q2jbi_156",pe="_filterSelect_q2jbi_162",_e="_timeline_q2jbi_149",je="_timelineEntry_q2jbi_182",be="_timelineTime_q2jbi_199",ve="_timelineIcon_q2jbi_207",Se="_timelineBody_q2jbi_212",Ce="_timelineSummary_q2jbi_217",Ne="_timelineTarget_q2jbi_224",Te="_timelineConfidence_q2jbi_231",ke="_confidenceExact_q2jbi_240",qe="_confidencePartial_q2jbi_245",we="_confidenceAfterOnly_q2jbi_250",Ie="_confidenceIntentOnly_q2jbi_255",Ee="_confidenceUnknown_q2jbi_260",Le="_timelineExpanded_q2jbi_266",$e="_empty_q2jbi_338",Oe="_loading_q2jbi_347",Re="_error_q2jbi_356",n={page:Q,header:X,backLink:Z,headerTitle:ee,headerTime:te,statusActive:ne,statusCompleted:ae,section:se,sectionTitle:ie,summaryGrid:ce,summaryCard:re,summaryCardActive:oe,summaryIcon:le,summaryCount:de,summaryLabel:me,contextGrid:ge,contextRow:he,contextKey:ue,contextValue:ye,timelineFilter:xe,filterLabel:fe,filterSelect:pe,timeline:_e,timelineEntry:je,timelineTime:be,timelineIcon:ve,timelineBody:Se,timelineSummary:Ce,timelineTarget:Ne,timelineConfidence:Te,confidenceExact:ke,confidencePartial:qe,confidenceAfterOnly:we,confidenceIntentOnly:Ie,confidenceUnknown:Ee,timelineExpanded:Le,empty:$e,loading:Oe,error:Re},B=[{key:"script",icon:"📝",labelKey:"changelog.category.script"},{key:"instance",icon:"🧱",labelKey:"changelog.category.instance"},{key:"property",icon:"🎨",labelKey:"changelog.category.property"},{key:"lighting",icon:"🌅",labelKey:"changelog.category.lighting"},{key:"terrain",icon:"⛰️",labelKey:"changelog.category.terrain"},{key:"asset",icon:"📦",labelKey:"changelog.category.asset"}];function K(t){if(!t)return"--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function Ae(t){if(!t)return"--:--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}:${String(i.getSeconds()).padStart(2,"0")}`}function Ke(t,i){if(!t||!i)return"";const o=new Date(i).getTime()-new Date(t).getTime();return o<0?"":`${Math.round(o/6e4)}min`}function Me(t){switch(t){case"exact":return n.confidenceExact;case"partial":return n.confidencePartial;case"after-only":return n.confidenceAfterOnly;case"intent-only":return n.confidenceIntentOnly;default:return n.confidenceUnknown}}function Be(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact","Exact");case"partial":return t("changelog.detail.confidence.partial","Partial");case"after-only":return t("changelog.detail.confidence.afterOnly","After only");case"intent-only":return t("changelog.detail.confidence.intentOnly","Intent only");default:return t("changelog.detail.confidence.unknown","Unknown")}}function Ve(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact.tooltip","Both the before and after state were confirmed for this change.");case"partial":return t("changelog.detail.confidence.partial.tooltip","Only part of the before and after state could be confirmed for this change.");case"after-only":return t("changelog.detail.confidence.afterOnly.tooltip","Only the resulting state after the change could be confirmed.");case"intent-only":return t("changelog.detail.confidence.intentOnly.tooltip","Only the requested action was recorded, not the resulting state.");default:return t("changelog.detail.confidence.unknown.tooltip","This change could not be confidently classified from the available data.")}}function Ge(t){const i=new URLSearchParams(t).get("placeId");if(!i)return null;const o=Number.parseInt(i,10);return Number.isInteger(o)&&o>=0?o:null}function He(){var p,_,j,b,v,S,C,N,T,k,u,q,y,m;const{t}=V(),{id:i}=G(),o=D(),h=F(),I=r.useMemo(()=>Ge(h.search),[h.search]),a=Y(i,I),[d,x]=r.useState("all"),[E,L]=r.useState(null),f=r.useMemo(()=>[...d==="all"?a.changes:a.changes.filter(c=>c.category===d)].reverse(),[a.changes,d]);if(a.loading)return e.jsx("div",{className:n.loading,children:t("common.loading","Loading...")});if(a.error)return e.jsxs("div",{className:n.error,children:[a.error,e.jsx("br",{}),e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const $=Ke(a.startTime,a.endTime),O=a.endTime?`${K(a.startTime)} → ${K(a.endTime)} (${$})`:`${K(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,R=!!((p=a.contextSummary)!=null&&p.intent||(_=a.contextSummary)!=null&&_.testScenario||(j=a.contextSummary)!=null&&j.expectedBehavior||(b=a.contextSummary)!=null&&b.observedBehavior),A=!!((v=a.verificationSummary)!=null&&v.label||(S=a.verificationSummary)!=null&&S.status||(C=a.verificationSummary)!=null&&C.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:O}),e.jsx(g,{text:a.status==="active"?t("changelog.card.active.tooltip","This session is still receiving new game changes."):t("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:a.status==="active"?n.statusActive:n.statusCompleted,children:a.status==="active"?t("changelog.card.active","Active"):t("changelog.card.completed","Completed")})})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:t("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:n.summaryGrid,children:B.map(s=>{const c=a.changeSummary;let l;switch(s.key){case"script":l=c.scriptsModified+c.scriptsCreated;break;case"instance":l=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":l=c.propertiesChanged;break;case"lighting":l=c.lightingChanged?1:0;break;case"terrain":l=c.terrainChanged?1:0;break;case"asset":l=c.assetsInserted;break;default:l=0}const M=d===s.key;return e.jsxs("div",{className:`${n.summaryCard} ${M?n.summaryCardActive:""}`,onClick:()=>x(M?"all":s.key),children:[e.jsx("span",{className:n.summaryIcon,children:s.icon}),e.jsx("div",{className:n.summaryCount,children:l}),e.jsx("div",{className:n.summaryLabel,children:t(s.labelKey,s.key)})]},s.key)})})]}),R&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:t("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:n.contextGrid,children:[((N=a.contextSummary)==null?void 0:N.intent)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.intent})]}),((T=a.contextSummary)==null?void 0:T.testScenario)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.why","Why this test ran")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.testScenario})]}),((k=a.contextSummary)==null?void 0:k.expectedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.expected","Expected")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.expectedBehavior})]}),((u=a.contextSummary)==null?void 0:u.observedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.observed","Observed")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.observedBehavior})]})]})]}),A&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:t("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:n.contextGrid,children:[((q=a.verificationSummary)==null?void 0:q.label)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.label","Result")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.label})]}),((y=a.verificationSummary)==null?void 0:y.status)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.status","Status")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.status})]}),((m=a.verificationSummary)==null?void 0:m.testTimestamp)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:t("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:n.timelineFilter,children:[e.jsx("span",{className:n.filterLabel,children:e.jsx(P,{label:`${t("changelog.detail.filterCategory","Category")}:`,tooltip:t("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:n.filterSelect,value:d,onChange:s=>x(s.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),B.map(s=>e.jsxs("option",{value:s.key,children:[s.icon," ",t(s.labelKey,s.key)]},s.key))]})]}),f.length===0?e.jsx("div",{className:n.empty,children:t("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:n.timeline,children:f.map((s,c)=>{const l=E===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>L(l?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Ae(s.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:J(s.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[s.summary,e.jsx(g,{text:Ve(t,s.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Me(s.confidence)}`,children:Be(t,s.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:s.target})]})]}),l&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(U,{change:s})})]},c)})})]})]})}export{He as Component};
1
+ import{r,a as w,u as V,b as G,c as D,d as F,j as e}from"./index-CnXGGM07.js";import{I as P}from"./InfoLabel-BAhsgLcj.js";import{G as U}from"./GameChangeDetail-CMSmIwO-.js";import{T as g}from"./TooltipText-CGH7dKN6.js";function H(t){const i={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const o of t)switch(o.category){case"script":o.changeType==="create"?i.scriptsCreated++:i.scriptsModified++;break;case"instance":o.changeType==="create"?i.instancesCreated++:o.changeType==="delete"?i.instancesDeleted++:o.changeType==="move"&&i.instancesMoved++;break;case"property":i.propertiesChanged++;break;case"lighting":i.lightingChanged=!0;break;case"terrain":i.terrainChanged=!0;break;case"asset":i.assetsInserted++;break}return i}function W(t){if(typeof t=="number")return{placeId:String(t)}}function Y(t,i){const[o,h]=r.useState(""),[I,a]=r.useState(""),[d,x]=r.useState(),[E,L]=r.useState("completed"),[f,$]=r.useState([]),[O,R]=r.useState([]),[A,p]=r.useState([]),[_,j]=r.useState(),[b,v]=r.useState(),[S,C]=r.useState(),[N,T]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[k,u]=r.useState(!0),[q,y]=r.useState(null),m=r.useCallback(async()=>{if(t){u(!0),y(null);try{const s=W(i),[c,l]=await Promise.all([s?w.get(`/api/dashboard/changelog/${t}`,s):w.get(`/api/dashboard/changelog/${t}`),s?w.get(`/api/dashboard/changelog/${t}/changes`,s):w.get(`/api/dashboard/changelog/${t}/changes`)]);h(c.entryId),a(c.startTime),x(c.endTime),L(c.status),$(c.entries),R(c.failures),j(c.contextSummary),v(c.replayMetadata),C(c.verificationSummary),p(l.changes),T(H(l.changes))}catch(s){y(s instanceof Error?s.message:"Failed to load changelog detail")}finally{u(!1)}}},[t,i]);return r.useEffect(()=>{m()},[m]),{entryId:o,startTime:I,endTime:d,status:E,entries:f,failures:O,changes:A,changeSummary:N,contextSummary:_,replayMetadata:b,verificationSummary:S,loading:k,error:q,refresh:m}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function J(t){return z[t]??"❓"}const Q="_page_q2jbi_2",X="_header_q2jbi_10",Z="_backLink_q2jbi_16",ee="_headerTitle_q2jbi_29",te="_headerTime_q2jbi_37",ne="_statusActive_q2jbi_44",ae="_statusCompleted_q2jbi_49",se="_section_q2jbi_54",ie="_sectionTitle_q2jbi_61",ce="_summaryGrid_q2jbi_74",re="_summaryCard_q2jbi_80",oe="_summaryCardActive_q2jbi_94",le="_summaryIcon_q2jbi_99",de="_summaryCount_q2jbi_105",me="_summaryLabel_q2jbi_112",ge="_contextGrid_q2jbi_121",he="_contextRow_q2jbi_127",ue="_contextKey_q2jbi_133",ye="_contextValue_q2jbi_141",xe="_timelineFilter_q2jbi_149",fe="_filterLabel_q2jbi_156",pe="_filterSelect_q2jbi_162",_e="_timeline_q2jbi_149",je="_timelineEntry_q2jbi_182",be="_timelineTime_q2jbi_199",ve="_timelineIcon_q2jbi_207",Se="_timelineBody_q2jbi_212",Ce="_timelineSummary_q2jbi_217",Ne="_timelineTarget_q2jbi_224",Te="_timelineConfidence_q2jbi_231",ke="_confidenceExact_q2jbi_240",qe="_confidencePartial_q2jbi_245",we="_confidenceAfterOnly_q2jbi_250",Ie="_confidenceIntentOnly_q2jbi_255",Ee="_confidenceUnknown_q2jbi_260",Le="_timelineExpanded_q2jbi_266",$e="_empty_q2jbi_338",Oe="_loading_q2jbi_347",Re="_error_q2jbi_356",n={page:Q,header:X,backLink:Z,headerTitle:ee,headerTime:te,statusActive:ne,statusCompleted:ae,section:se,sectionTitle:ie,summaryGrid:ce,summaryCard:re,summaryCardActive:oe,summaryIcon:le,summaryCount:de,summaryLabel:me,contextGrid:ge,contextRow:he,contextKey:ue,contextValue:ye,timelineFilter:xe,filterLabel:fe,filterSelect:pe,timeline:_e,timelineEntry:je,timelineTime:be,timelineIcon:ve,timelineBody:Se,timelineSummary:Ce,timelineTarget:Ne,timelineConfidence:Te,confidenceExact:ke,confidencePartial:qe,confidenceAfterOnly:we,confidenceIntentOnly:Ie,confidenceUnknown:Ee,timelineExpanded:Le,empty:$e,loading:Oe,error:Re},B=[{key:"script",icon:"📝",labelKey:"changelog.category.script"},{key:"instance",icon:"🧱",labelKey:"changelog.category.instance"},{key:"property",icon:"🎨",labelKey:"changelog.category.property"},{key:"lighting",icon:"🌅",labelKey:"changelog.category.lighting"},{key:"terrain",icon:"⛰️",labelKey:"changelog.category.terrain"},{key:"asset",icon:"📦",labelKey:"changelog.category.asset"}];function K(t){if(!t)return"--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function Ae(t){if(!t)return"--:--:--";const i=new Date(t);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}:${String(i.getSeconds()).padStart(2,"0")}`}function Ke(t,i){if(!t||!i)return"";const o=new Date(i).getTime()-new Date(t).getTime();return o<0?"":`${Math.round(o/6e4)}min`}function Me(t){switch(t){case"exact":return n.confidenceExact;case"partial":return n.confidencePartial;case"after-only":return n.confidenceAfterOnly;case"intent-only":return n.confidenceIntentOnly;default:return n.confidenceUnknown}}function Be(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact","Exact");case"partial":return t("changelog.detail.confidence.partial","Partial");case"after-only":return t("changelog.detail.confidence.afterOnly","After only");case"intent-only":return t("changelog.detail.confidence.intentOnly","Intent only");default:return t("changelog.detail.confidence.unknown","Unknown")}}function Ve(t,i){switch(i){case"exact":return t("changelog.detail.confidence.exact.tooltip","Both the before and after state were confirmed for this change.");case"partial":return t("changelog.detail.confidence.partial.tooltip","Only part of the before and after state could be confirmed for this change.");case"after-only":return t("changelog.detail.confidence.afterOnly.tooltip","Only the resulting state after the change could be confirmed.");case"intent-only":return t("changelog.detail.confidence.intentOnly.tooltip","Only the requested action was recorded, not the resulting state.");default:return t("changelog.detail.confidence.unknown.tooltip","This change could not be confidently classified from the available data.")}}function Ge(t){const i=new URLSearchParams(t).get("placeId");if(!i)return null;const o=Number.parseInt(i,10);return Number.isInteger(o)&&o>=0?o:null}function He(){var p,_,j,b,v,S,C,N,T,k,u,q,y,m;const{t}=V(),{id:i}=G(),o=D(),h=F(),I=r.useMemo(()=>Ge(h.search),[h.search]),a=Y(i,I),[d,x]=r.useState("all"),[E,L]=r.useState(null),f=r.useMemo(()=>[...d==="all"?a.changes:a.changes.filter(c=>c.category===d)].reverse(),[a.changes,d]);if(a.loading)return e.jsx("div",{className:n.loading,children:t("common.loading","Loading...")});if(a.error)return e.jsxs("div",{className:n.error,children:[a.error,e.jsx("br",{}),e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const $=Ke(a.startTime,a.endTime),O=a.endTime?`${K(a.startTime)} → ${K(a.endTime)} (${$})`:`${K(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,R=!!((p=a.contextSummary)!=null&&p.intent||(_=a.contextSummary)!=null&&_.testScenario||(j=a.contextSummary)!=null&&j.expectedBehavior||(b=a.contextSummary)!=null&&b.observedBehavior),A=!!((v=a.verificationSummary)!=null&&v.label||(S=a.verificationSummary)!=null&&S.status||(C=a.verificationSummary)!=null&&C.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>o("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:O}),e.jsx(g,{text:a.status==="active"?t("changelog.card.active.tooltip","This session is still receiving new game changes."):t("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),children:e.jsx("span",{className:a.status==="active"?n.statusActive:n.statusCompleted,children:a.status==="active"?t("changelog.card.active","Active"):t("changelog.card.completed","Completed")})})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeSummary.tooltip","Counts of extracted game changes grouped by category for this session."),children:e.jsx("span",{children:t("changelog.detail.changeSummary","Change Summary")})})}),e.jsx("div",{className:n.summaryGrid,children:B.map(s=>{const c=a.changeSummary;let l;switch(s.key){case"script":l=c.scriptsModified+c.scriptsCreated;break;case"instance":l=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":l=c.propertiesChanged;break;case"lighting":l=c.lightingChanged?1:0;break;case"terrain":l=c.terrainChanged?1:0;break;case"asset":l=c.assetsInserted;break;default:l=0}const M=d===s.key;return e.jsxs("div",{className:`${n.summaryCard} ${M?n.summaryCardActive:""}`,onClick:()=>x(M?"all":s.key),children:[e.jsx("span",{className:n.summaryIcon,children:s.icon}),e.jsx("div",{className:n.summaryCount,children:l}),e.jsx("div",{className:n.summaryLabel,children:t(s.labelKey,s.key)})]},s.key)})})]}),R&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.context.tooltip","Structured execution context captured for this changelog session."),children:e.jsx("span",{children:t("changelog.detail.context.title","Context Summary")})})}),e.jsxs("div",{className:n.contextGrid,children:[((N=a.contextSummary)==null?void 0:N.intent)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.intent})]}),((T=a.contextSummary)==null?void 0:T.testScenario)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.why","Why this test ran")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.testScenario})]}),((k=a.contextSummary)==null?void 0:k.expectedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.expected","Expected")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.expectedBehavior})]}),((u=a.contextSummary)==null?void 0:u.observedBehavior)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("playtest.context.observed","Observed")}),e.jsx("span",{className:n.contextValue,children:a.contextSummary.observedBehavior})]})]})]}),A&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.verification.tooltip","Verification signals linked to this changelog session."),children:e.jsx("span",{children:t("changelog.detail.verification.title","Verification")})})}),e.jsxs("div",{className:n.contextGrid,children:[((q=a.verificationSummary)==null?void 0:q.label)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.label","Result")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.label})]}),((y=a.verificationSummary)==null?void 0:y.status)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.status","Status")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.status})]}),((m=a.verificationSummary)==null?void 0:m.testTimestamp)&&e.jsxs("div",{className:n.contextRow,children:[e.jsx("span",{className:n.contextKey,children:t("changelog.detail.verification.timestamp","Recorded at")}),e.jsx("span",{className:n.contextValue,children:a.verificationSummary.testTimestamp})]})]})]}),e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(g,{text:t("changelog.detail.changeTimeline.tooltip","Chronological list of extracted game changes for this session."),children:e.jsx("span",{children:t("changelog.detail.changeTimeline","Change Timeline")})})}),e.jsxs("div",{className:n.timelineFilter,children:[e.jsx("span",{className:n.filterLabel,children:e.jsx(P,{label:`${t("changelog.detail.filterCategory","Category")}:`,tooltip:t("changelog.detail.filterCategory.tooltip","Filter the timeline to a single change category.")})}),e.jsxs("select",{className:n.filterSelect,value:d,onChange:s=>x(s.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),B.map(s=>e.jsxs("option",{value:s.key,children:[s.icon," ",t(s.labelKey,s.key)]},s.key))]})]}),f.length===0?e.jsx("div",{className:n.empty,children:t("changelog.detail.noChanges","No changes in this category")}):e.jsx("div",{className:n.timeline,children:f.map((s,c)=>{const l=E===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>L(l?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Ae(s.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:J(s.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[s.summary,e.jsx(g,{text:Ve(t,s.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Me(s.confidence)}`,children:Be(t,s.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:s.target})]})]}),l&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(U,{change:s})})]},c)})})]})]})}export{He as Component};
@@ -1 +1 @@
1
- import{r as l,a as F,D,u as M,j as e,e as O,c as V,h as U,l as K,T as G}from"./index-BDJHcdyQ.js";import{P as H}from"./PageHeader-B0qiATU4.js";import{C as Z}from"./ConfirmModal-CEmy8izm.js";import{C as Q}from"./CurrentPlaceScope-CuZXV9Ku.js";import{T as k}from"./TooltipText-DaLR7eg1.js";import{T as q}from"./Tabs-DqGYr78-.js";import"./ConfirmModal.module-D1aZY2bQ.js";const z=10;function J(t,o){return typeof o!="number"?t:`${t}?placeId=${encodeURIComponent(String(o))}`}function W(t){const o=(t==null?void 0:t.placeId)??null,[s,n]=l.useState([]),[u,_]=l.useState(0),[a,f]=l.useState(!1),[x,v]=l.useState(!0),[g,C]=l.useState(0),[d,y]=l.useState("all"),N=l.useRef(null),m=l.useCallback(async(h,b)=>{v(!0);try{const j={limit:String(z),offset:String(h)};b!=="all"&&(j.status=b),typeof o=="number"&&(j.placeId=String(o));const I=await F.get("/api/dashboard/changelog",j);n(I.entries),_(I.total),f(I.hasMore)}catch{n([]),_(0),f(!1)}finally{v(!1)}},[o]),S=l.useCallback(()=>{m(g,d)},[m,g,d]),i=l.useCallback(async()=>{await F.post(J("/api/dashboard/changelog/clear",o)),n([]),_(0),f(!1)},[o]);return l.useEffect(()=>{m(g,d)},[m,g,d]),l.useEffect(()=>{const h=new D;N.current=h,h.connect();const b=h.on("command",()=>{m(g,d)});return()=>{b(),h.disconnect(),N.current=null}},[m,g,d]),{entries:s,total:u,hasMore:a,loading:x,offset:g,statusFilter:d,setOffset:C,setStatusFilter:y,refresh:S,clear:i}}const X="_card_1n89u_2",Y="_header_1n89u_17",ee="_statusBadge_1n89u_24",te="_statusDot_1n89u_35",se="_active_1n89u_41",ae="_completed_1n89u_50",ne="_timeRange_1n89u_58",ce="_summaryList_1n89u_65",oe="_summaryItem_1n89u_71",ie="_summaryIcon_1n89u_80",le="_summaryText_1n89u_86",re="_progressBar_1n89u_91",ge="_progressFill_1n89u_99",de="_emptySummary_1n89u_112",me="_contextBlock_1n89u_120",he="_contextLabel_1n89u_129",pe="_contextValue_1n89u_137",c={card:X,header:Y,statusBadge:ee,statusDot:te,active:se,completed:ae,timeRange:ne,summaryList:ce,summaryItem:oe,summaryIcon:ie,summaryText:le,progressBar:re,progressFill:ge,emptySummary:de,contextBlock:me,contextLabel:he,contextValue:pe};function R(t){if(!t)return"--:--";const o=new Date(t);return`${String(o.getHours()).padStart(2,"0")}:${String(o.getMinutes()).padStart(2,"0")}`}function ue({entry:t,onClick:o}){var h,b,j,I,B,L,A,P,w,E;const{t:s}=M(),n=t.changeSummary,u=t.status==="active",_=t.isBootstrapOnly===!0,a=[],f=n.scriptsModified+n.scriptsCreated;if(f>0){const p=[];n.scriptsModified>0&&p.push(`${n.scriptsModified} ${s("changelog.card.modified","modified")}`),n.scriptsCreated>0&&p.push(`${n.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${f} ${s("changelog.card.scripts","scripts")} ${p.join(", ")}`;a.push({icon:"📝",text:T,tooltip:s("changelog.card.scripts.tooltip","Script changes made in this session.")})}const x=n.instancesCreated+n.instancesDeleted+n.instancesMoved;if(x>0){const p=[];n.instancesCreated>0&&p.push(`${n.instancesCreated} ${s("changelog.card.created","created")}`),n.instancesDeleted>0&&p.push(`${n.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),n.instancesMoved>0&&p.push(`${n.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${x} ${s("changelog.card.instances","instances")} ${p.join(", ")}`;a.push({icon:"🧱",text:T,tooltip:s("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}n.propertiesChanged>0&&a.push({icon:"🎨",text:`${n.propertiesChanged} ${s("changelog.card.propertiesChanged","properties changed")}`,tooltip:s("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),n.lightingChanged&&a.push({icon:"🌅",text:s("changelog.card.lightingConfigured","Lighting configured"),tooltip:s("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),n.terrainChanged&&a.push({icon:"⛰️",text:s("changelog.card.terrainConfigured","Terrain configured"),tooltip:s("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),n.assetsInserted>0&&a.push({icon:"📦",text:`${n.assetsInserted} ${s("changelog.card.assetsInserted","assets inserted")}`,tooltip:s("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const v=R(t.startTime),g=u?s("changelog.card.inProgress","in progress"):t.endTime?R(t.endTime):"--:--",C=_?s("changelog.card.bootstrapStatus","Bootstrap"):u?s("changelog.card.active","Active"):s("changelog.card.completed","Completed"),d=_?s("changelog.card.bootstrapStatus.tooltip","This session only contains the initial sync bootstrap snapshot."):u?s("changelog.card.active.tooltip","This session is still receiving new game changes."):s("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),y=_?s("changelog.card.bootstrapSummary","Initial sync snapshot"):s("changelog.card.noChanges","No changes yet"),N=_?s("changelog.card.bootstrapSummary.tooltip","Initial file sync writes are collapsed into a single bootstrap snapshot row."):s("changelog.card.noChanges.tooltip","No game changes have been extracted for this session yet."),m=(b=(h=t.contextSummary)==null?void 0:h.intent)==null?void 0:b.trim(),S=((L=(B=(I=(j=t.contextSummary)==null?void 0:j.affectedAreas)==null?void 0:I[0])==null?void 0:B.label)==null?void 0:L.trim())||((P=(A=t.contextSummary)==null?void 0:A.testScenario)==null?void 0:P.trim()),i=(E=(w=t.verificationSummary)==null?void 0:w.label)==null?void 0:E.trim();return e.jsxs("div",{className:c.card,onClick:o,children:[e.jsxs("div",{className:c.header,children:[e.jsx(k,{text:d,children:e.jsxs("span",{className:`${c.statusBadge} ${u?c.active:c.completed}`,children:[e.jsx("span",{className:c.statusDot}),C]})}),e.jsxs("span",{className:c.timeRange,children:[v,"~",g]})]}),e.jsx("div",{className:c.summaryList,children:a.length>0?a.map((p,T)=>e.jsxs("div",{className:c.summaryItem,children:[e.jsx("span",{className:c.summaryIcon,children:p.icon}),e.jsx(k,{text:p.tooltip,children:e.jsx("span",{className:c.summaryText,children:p.text})})]},T)):e.jsx(k,{text:N,children:e.jsx("span",{className:c.emptySummary,style:{display:"block"},children:y})})}),m&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:c.contextValue,children:m})]}),!m&&S&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:c.contextValue,children:S})]}),i&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.verification","Verification")}),e.jsx("span",{className:c.contextValue,children:i})]}),u&&e.jsx("div",{className:c.progressBar,children:e.jsx("div",{className:c.progressFill})})]})}const _e="_page_1tggr_2",fe="_limitNotice_1tggr_9",xe="_limitNoticeContent_1tggr_23",ye="_limitNoticeTitle_1tggr_28",be="_limitNoticeText_1tggr_35",ve="_primaryAction_1tggr_41",Ce="_clearButton_1tggr_67",Ne="_list_1tggr_88",Se="_empty_1tggr_95",je="_loading_1tggr_104",Ie="_pagination_1tggr_113",Te="_pageInfo_1tggr_121",$e="_btn_1tggr_127",r={page:_e,limitNotice:fe,limitNoticeContent:xe,limitNoticeTitle:ye,limitNoticeText:be,primaryAction:ve,clearButton:Ce,list:Ne,empty:Se,loading:je,pagination:Ie,pageInfo:Te,btn:$e},$=10;function ke(t,o){return typeof o!="number"?`/changelog/${t}`:`/changelog/${t}?placeId=${encodeURIComponent(String(o))}`}const Be=[{key:"all",labelKey:"changelog.filter.all"},{key:"active",labelKey:"changelog.filter.active"},{key:"completed",labelKey:"changelog.filter.completed"}];function Me(){const{t}=M(),{trackEvent:o,trackPageView:s}=O(),n=V(),[u,_]=l.useState(null),a=W({placeId:u}),f=U(),{show:x}=K(),[v,g]=l.useState(!1),[C,d]=l.useState(!1),y=!f.loading&&f.tier==="basic",N=y?a.entries.slice(0,3):a.entries,m=!y&&a.total>$,S=async()=>{d(!0);try{await a.clear(),x(t("toast.clearSuccess","Cleared successfully"),"success"),g(!1)}catch{x(t("toast.clearFailed","Failed to clear data"),"error")}finally{d(!1)}};return e.jsxs("div",{className:r.page,children:[e.jsx(H,{title:t("page.changelog.title","Changelog"),description:t("page.changelog.description","Review game-change sessions captured from AI actions and sync events."),helpTopicId:"changelog",helpState:{tier:f.tier}}),e.jsx(Q,{surface:"changelog",selectable:!0,selectedPlaceId:u,onSelectedPlaceIdChange:i=>{_(i),a.setOffset(0)}}),e.jsx(q,{items:Be.map(i=>({key:i.key,label:t(i.labelKey,i.key.charAt(0).toUpperCase()+i.key.slice(1))})),value:a.statusFilter,onChange:i=>{const h=`changelog_${i}`;o("dashboard_click_event",{click_target:`changelog_tab_${i}`,page:"changelog",tab:h}),s({page:"changelog",tab:h}),a.setStatusFilter(i),a.setOffset(0)},rightActions:e.jsx("button",{className:r.clearButton,onClick:()=>{o("dashboard_click_event",{click_target:"changelog_clear",page:"changelog",tab:`changelog_${a.statusFilter}`}),g(!0)},children:t("common.clear","Clear")})}),a.loading&&a.entries.length===0&&e.jsx("div",{className:r.loading,children:t("common.loading","Loading...")}),!a.loading&&a.entries.length===0?e.jsx("div",{className:r.empty,children:t("changelog.empty","No changelog entries for the current place yet")}):e.jsx("div",{className:r.list,children:N.map(i=>e.jsx(ue,{entry:i,onClick:()=>n(ke(i.entryId,u))},i.entryId))}),m&&e.jsxs("div",{className:r.pagination,children:[e.jsx("button",{className:r.btn,disabled:a.offset===0,onClick:()=>a.setOffset(Math.max(0,a.offset-$)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:r.pageInfo,children:[a.offset+1,"–",Math.min(a.offset+$,a.total)," / ",a.total]}),e.jsx("button",{className:r.btn,disabled:!a.hasMore,onClick:()=>a.setOffset(a.offset+$),children:t("tools.page.next","Next")})]}),y&&e.jsx(e.Fragment,{children:e.jsxs("div",{className:r.limitNotice,children:[e.jsxs("div",{className:r.limitNoticeContent,children:[e.jsx("div",{className:r.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:r.limitNoticeText,children:t("changelog.basic.limit.body","Full changelog timeline browsing is available with Pro.")})]}),e.jsx("a",{className:r.primaryAction,href:G.changelog,target:"_blank",rel:"noreferrer",onClick:()=>o("dashboard_click_event",{click_target:"upgrade_cta",placement:"changelog_limit_notice",page:"changelog",tab:`changelog_${a.statusFilter}`}),children:t("tier.upgrade","View Pro")})]})}),e.jsx(Z,{open:v,title:t("changelog.clear.title","Clear changelog?"),message:t("changelog.clear.message","This permanently removes the stored changelog for the current place."),cancelLabel:t("common.cancel","Cancel"),confirmLabel:t("common.clear","Clear"),loading:C,onCancel:()=>!C&&g(!1),onConfirm:S})]})}export{Me as Component};
1
+ import{r as l,a as F,D,u as M,j as e,e as O,c as V,h as U,l as K,T as G}from"./index-CnXGGM07.js";import{P as H}from"./PageHeader-Bfy2f-GH.js";import{C as Z}from"./ConfirmModal-BqCEvp7Y.js";import{C as Q}from"./CurrentPlaceScope-C8U9I15o.js";import{T as k}from"./TooltipText-CGH7dKN6.js";import{T as q}from"./Tabs-Ccrw7Hjb.js";import"./ConfirmModal.module-D1aZY2bQ.js";const z=10;function J(t,o){return typeof o!="number"?t:`${t}?placeId=${encodeURIComponent(String(o))}`}function W(t){const o=(t==null?void 0:t.placeId)??null,[s,n]=l.useState([]),[u,_]=l.useState(0),[a,f]=l.useState(!1),[x,v]=l.useState(!0),[g,C]=l.useState(0),[d,y]=l.useState("all"),N=l.useRef(null),m=l.useCallback(async(h,b)=>{v(!0);try{const j={limit:String(z),offset:String(h)};b!=="all"&&(j.status=b),typeof o=="number"&&(j.placeId=String(o));const I=await F.get("/api/dashboard/changelog",j);n(I.entries),_(I.total),f(I.hasMore)}catch{n([]),_(0),f(!1)}finally{v(!1)}},[o]),S=l.useCallback(()=>{m(g,d)},[m,g,d]),i=l.useCallback(async()=>{await F.post(J("/api/dashboard/changelog/clear",o)),n([]),_(0),f(!1)},[o]);return l.useEffect(()=>{m(g,d)},[m,g,d]),l.useEffect(()=>{const h=new D;N.current=h,h.connect();const b=h.on("command",()=>{m(g,d)});return()=>{b(),h.disconnect(),N.current=null}},[m,g,d]),{entries:s,total:u,hasMore:a,loading:x,offset:g,statusFilter:d,setOffset:C,setStatusFilter:y,refresh:S,clear:i}}const X="_card_1n89u_2",Y="_header_1n89u_17",ee="_statusBadge_1n89u_24",te="_statusDot_1n89u_35",se="_active_1n89u_41",ae="_completed_1n89u_50",ne="_timeRange_1n89u_58",ce="_summaryList_1n89u_65",oe="_summaryItem_1n89u_71",ie="_summaryIcon_1n89u_80",le="_summaryText_1n89u_86",re="_progressBar_1n89u_91",ge="_progressFill_1n89u_99",de="_emptySummary_1n89u_112",me="_contextBlock_1n89u_120",he="_contextLabel_1n89u_129",pe="_contextValue_1n89u_137",c={card:X,header:Y,statusBadge:ee,statusDot:te,active:se,completed:ae,timeRange:ne,summaryList:ce,summaryItem:oe,summaryIcon:ie,summaryText:le,progressBar:re,progressFill:ge,emptySummary:de,contextBlock:me,contextLabel:he,contextValue:pe};function R(t){if(!t)return"--:--";const o=new Date(t);return`${String(o.getHours()).padStart(2,"0")}:${String(o.getMinutes()).padStart(2,"0")}`}function ue({entry:t,onClick:o}){var h,b,j,I,B,L,A,P,w,E;const{t:s}=M(),n=t.changeSummary,u=t.status==="active",_=t.isBootstrapOnly===!0,a=[],f=n.scriptsModified+n.scriptsCreated;if(f>0){const p=[];n.scriptsModified>0&&p.push(`${n.scriptsModified} ${s("changelog.card.modified","modified")}`),n.scriptsCreated>0&&p.push(`${n.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${f} ${s("changelog.card.scripts","scripts")} ${p.join(", ")}`;a.push({icon:"📝",text:T,tooltip:s("changelog.card.scripts.tooltip","Script changes made in this session.")})}const x=n.instancesCreated+n.instancesDeleted+n.instancesMoved;if(x>0){const p=[];n.instancesCreated>0&&p.push(`${n.instancesCreated} ${s("changelog.card.created","created")}`),n.instancesDeleted>0&&p.push(`${n.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),n.instancesMoved>0&&p.push(`${n.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${x} ${s("changelog.card.instances","instances")} ${p.join(", ")}`;a.push({icon:"🧱",text:T,tooltip:s("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}n.propertiesChanged>0&&a.push({icon:"🎨",text:`${n.propertiesChanged} ${s("changelog.card.propertiesChanged","properties changed")}`,tooltip:s("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),n.lightingChanged&&a.push({icon:"🌅",text:s("changelog.card.lightingConfigured","Lighting configured"),tooltip:s("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),n.terrainChanged&&a.push({icon:"⛰️",text:s("changelog.card.terrainConfigured","Terrain configured"),tooltip:s("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),n.assetsInserted>0&&a.push({icon:"📦",text:`${n.assetsInserted} ${s("changelog.card.assetsInserted","assets inserted")}`,tooltip:s("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const v=R(t.startTime),g=u?s("changelog.card.inProgress","in progress"):t.endTime?R(t.endTime):"--:--",C=_?s("changelog.card.bootstrapStatus","Bootstrap"):u?s("changelog.card.active","Active"):s("changelog.card.completed","Completed"),d=_?s("changelog.card.bootstrapStatus.tooltip","This session only contains the initial sync bootstrap snapshot."):u?s("changelog.card.active.tooltip","This session is still receiving new game changes."):s("changelog.card.completed.tooltip","This session has ended and no more changes are expected."),y=_?s("changelog.card.bootstrapSummary","Initial sync snapshot"):s("changelog.card.noChanges","No changes yet"),N=_?s("changelog.card.bootstrapSummary.tooltip","Initial file sync writes are collapsed into a single bootstrap snapshot row."):s("changelog.card.noChanges.tooltip","No game changes have been extracted for this session yet."),m=(b=(h=t.contextSummary)==null?void 0:h.intent)==null?void 0:b.trim(),S=((L=(B=(I=(j=t.contextSummary)==null?void 0:j.affectedAreas)==null?void 0:I[0])==null?void 0:B.label)==null?void 0:L.trim())||((P=(A=t.contextSummary)==null?void 0:A.testScenario)==null?void 0:P.trim()),i=(E=(w=t.verificationSummary)==null?void 0:w.label)==null?void 0:E.trim();return e.jsxs("div",{className:c.card,onClick:o,children:[e.jsxs("div",{className:c.header,children:[e.jsx(k,{text:d,children:e.jsxs("span",{className:`${c.statusBadge} ${u?c.active:c.completed}`,children:[e.jsx("span",{className:c.statusDot}),C]})}),e.jsxs("span",{className:c.timeRange,children:[v,"~",g]})]}),e.jsx("div",{className:c.summaryList,children:a.length>0?a.map((p,T)=>e.jsxs("div",{className:c.summaryItem,children:[e.jsx("span",{className:c.summaryIcon,children:p.icon}),e.jsx(k,{text:p.tooltip,children:e.jsx("span",{className:c.summaryText,children:p.text})})]},T)):e.jsx(k,{text:N,children:e.jsx("span",{className:c.emptySummary,style:{display:"block"},children:y})})}),m&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:c.contextValue,children:m})]}),!m&&S&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:c.contextValue,children:S})]}),i&&e.jsxs("div",{className:c.contextBlock,children:[e.jsx("span",{className:c.contextLabel,children:s("changelog.card.verification","Verification")}),e.jsx("span",{className:c.contextValue,children:i})]}),u&&e.jsx("div",{className:c.progressBar,children:e.jsx("div",{className:c.progressFill})})]})}const _e="_page_1tggr_2",fe="_limitNotice_1tggr_9",xe="_limitNoticeContent_1tggr_23",ye="_limitNoticeTitle_1tggr_28",be="_limitNoticeText_1tggr_35",ve="_primaryAction_1tggr_41",Ce="_clearButton_1tggr_67",Ne="_list_1tggr_88",Se="_empty_1tggr_95",je="_loading_1tggr_104",Ie="_pagination_1tggr_113",Te="_pageInfo_1tggr_121",$e="_btn_1tggr_127",r={page:_e,limitNotice:fe,limitNoticeContent:xe,limitNoticeTitle:ye,limitNoticeText:be,primaryAction:ve,clearButton:Ce,list:Ne,empty:Se,loading:je,pagination:Ie,pageInfo:Te,btn:$e},$=10;function ke(t,o){return typeof o!="number"?`/changelog/${t}`:`/changelog/${t}?placeId=${encodeURIComponent(String(o))}`}const Be=[{key:"all",labelKey:"changelog.filter.all"},{key:"active",labelKey:"changelog.filter.active"},{key:"completed",labelKey:"changelog.filter.completed"}];function Me(){const{t}=M(),{trackEvent:o,trackPageView:s}=O(),n=V(),[u,_]=l.useState(null),a=W({placeId:u}),f=U(),{show:x}=K(),[v,g]=l.useState(!1),[C,d]=l.useState(!1),y=!f.loading&&f.tier==="basic",N=y?a.entries.slice(0,3):a.entries,m=!y&&a.total>$,S=async()=>{d(!0);try{await a.clear(),x(t("toast.clearSuccess","Cleared successfully"),"success"),g(!1)}catch{x(t("toast.clearFailed","Failed to clear data"),"error")}finally{d(!1)}};return e.jsxs("div",{className:r.page,children:[e.jsx(H,{title:t("page.changelog.title","Changelog"),description:t("page.changelog.description","Review game-change sessions captured from AI actions and sync events."),helpTopicId:"changelog",helpState:{tier:f.tier}}),e.jsx(Q,{surface:"changelog",selectable:!0,selectedPlaceId:u,onSelectedPlaceIdChange:i=>{_(i),a.setOffset(0)}}),e.jsx(q,{items:Be.map(i=>({key:i.key,label:t(i.labelKey,i.key.charAt(0).toUpperCase()+i.key.slice(1))})),value:a.statusFilter,onChange:i=>{const h=`changelog_${i}`;o("dashboard_click_event",{click_target:`changelog_tab_${i}`,page:"changelog",tab:h}),s({page:"changelog",tab:h}),a.setStatusFilter(i),a.setOffset(0)},rightActions:e.jsx("button",{className:r.clearButton,onClick:()=>{o("dashboard_click_event",{click_target:"changelog_clear",page:"changelog",tab:`changelog_${a.statusFilter}`}),g(!0)},children:t("common.clear","Clear")})}),a.loading&&a.entries.length===0&&e.jsx("div",{className:r.loading,children:t("common.loading","Loading...")}),!a.loading&&a.entries.length===0?e.jsx("div",{className:r.empty,children:t("changelog.empty","No changelog entries for the current place yet")}):e.jsx("div",{className:r.list,children:N.map(i=>e.jsx(ue,{entry:i,onClick:()=>n(ke(i.entryId,u))},i.entryId))}),m&&e.jsxs("div",{className:r.pagination,children:[e.jsx("button",{className:r.btn,disabled:a.offset===0,onClick:()=>a.setOffset(Math.max(0,a.offset-$)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:r.pageInfo,children:[a.offset+1,"–",Math.min(a.offset+$,a.total)," / ",a.total]}),e.jsx("button",{className:r.btn,disabled:!a.hasMore,onClick:()=>a.setOffset(a.offset+$),children:t("tools.page.next","Next")})]}),y&&e.jsx(e.Fragment,{children:e.jsxs("div",{className:r.limitNotice,children:[e.jsxs("div",{className:r.limitNoticeContent,children:[e.jsx("div",{className:r.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:r.limitNoticeText,children:t("changelog.basic.limit.body","Full changelog timeline browsing is available with Pro.")})]}),e.jsx("a",{className:r.primaryAction,href:G.changelog,target:"_blank",rel:"noreferrer",onClick:()=>o("dashboard_click_event",{click_target:"upgrade_cta",placement:"changelog_limit_notice",page:"changelog",tab:`changelog_${a.statusFilter}`}),children:t("tier.upgrade","View Pro")})]})}),e.jsx(Z,{open:v,title:t("changelog.clear.title","Clear changelog?"),message:t("changelog.clear.message","This permanently removes the stored changelog for the current place."),cancelLabel:t("common.cancel","Cancel"),confirmLabel:t("common.clear","Clear"),loading:C,onCancel:()=>!C&&g(!1),onConfirm:S})]})}export{Me as Component};
@@ -1 +1 @@
1
- import{r as u,j as s}from"./index-BDJHcdyQ.js";import{s as a}from"./ConfirmModal.module-D1aZY2bQ.js";function p({open:r,title:t,message:o,cancelLabel:c,confirmLabel:n,loading:e=!1,onCancel:l,onConfirm:d}){const i=u.useId();return r?s.jsx("div",{className:a.backdrop,onClick:e?void 0:l,children:s.jsxs("div",{className:a.modal,role:"dialog","aria-modal":"true","aria-labelledby":i,onClick:m=>m.stopPropagation(),children:[s.jsx("h2",{id:i,className:a.title,children:t}),s.jsx("p",{className:a.message,children:o}),s.jsxs("div",{className:a.actions,children:[s.jsx("button",{className:a.cancelButton,onClick:l,disabled:e,children:c}),s.jsx("button",{className:a.confirmButton,onClick:d,disabled:e,children:e?"...":n})]})]})}):null}export{p as C};
1
+ import{r as u,j as s}from"./index-CnXGGM07.js";import{s as a}from"./ConfirmModal.module-D1aZY2bQ.js";function p({open:r,title:t,message:o,cancelLabel:c,confirmLabel:n,loading:e=!1,onCancel:l,onConfirm:d}){const i=u.useId();return r?s.jsx("div",{className:a.backdrop,onClick:e?void 0:l,children:s.jsxs("div",{className:a.modal,role:"dialog","aria-modal":"true","aria-labelledby":i,onClick:m=>m.stopPropagation(),children:[s.jsx("h2",{id:i,className:a.title,children:t}),s.jsx("p",{className:a.message,children:o}),s.jsxs("div",{className:a.actions,children:[s.jsx("button",{className:a.cancelButton,onClick:l,disabled:e,children:c}),s.jsx("button",{className:a.confirmButton,onClick:d,disabled:e,children:e?"...":n})]})]})}):null}export{p as C};
@@ -0,0 +1 @@
1
+ ._container_1h084_2{max-height:200px;overflow-y:auto;font-family:var(--font-code);font-size:12px;line-height:1.6;padding:8px 12px;background:var(--bg-secondary);border-radius:4px}._entry_1h084_14{display:flex;gap:8px;white-space:nowrap}._timestamp_1h084_21{color:var(--text-muted);flex-shrink:0}._message_1h084_27{color:var(--text-primary);overflow:hidden;text-overflow:ellipsis}._warn_1h084_34 ._message_1h084_27{color:var(--warning)}._error_1h084_39 ._message_1h084_27{color:var(--error)}._empty_1h084_44{color:var(--text-muted);font-style:italic;padding:8px 0}._page_14kg9_2{display:flex;flex-direction:column;gap:16px;width:100%;max-width:1180px}._card_14kg9_11{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px}._topologyCard_14kg9_19{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px 20px}._topologyDisconnected_14kg9_26{border-color:var(--error-border)}._topologyHeader_14kg9_30{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:18px}._topologyIntro_14kg9_38{margin:-6px 0 0;color:var(--text-secondary);font-size:13px;line-height:1.5}._topologyNetwork_14kg9_45{position:relative}._topologyLinks_14kg9_49{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;width:100%;height:100%;pointer-events:none;overflow:visible}._topologyLink_14kg9_49{stroke:color-mix(in srgb,var(--accent) 62%,var(--border));stroke-linecap:round;stroke-width:1.5;opacity:.82}._topologyLink_agent_14kg9_66{stroke:color-mix(in srgb,var(--accent) 58%,var(--border))}._topologyLink_studio_14kg9_70{stroke:color-mix(in srgb,var(--accent) 66%,var(--border))}._topologyGrid_14kg9_74{position:relative;z-index:1;display:grid;grid-template-columns:minmax(220px,1fr) minmax(220px,.82fr) minmax(240px,1.18fr);align-items:start;gap:52px}._topologyColumn_14kg9_83{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyColumnHeader_14kg9_90{display:flex;align-items:center;gap:8px;min-height:28px;color:var(--text-primary);font-family:var(--font-label);font-size:12px;font-weight:700}._topologyColumnHeaderSpacer_14kg9_101{min-height:28px}._topologyCount_14kg9_105{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:20px;padding:0 6px;border-radius:var(--radius-pill);background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary);font-family:var(--font-code);font-size:11px}._topologyList_14kg9_120{display:flex;flex-direction:column;gap:8px;justify-content:flex-start;min-height:178px}._topologyListCentered_14kg9_128{justify-content:center}._topologyNode_14kg9_132{min-width:0;border:1px solid var(--border);border-radius:8px;background:var(--bg-secondary);padding:10px 12px}._topologyNodeTitle_14kg9_140{display:flex;align-items:center;min-width:0;gap:8px;color:var(--text-primary);font-family:var(--font-label);font-size:13px;font-weight:600}._topologyNodeTitle_14kg9_140 strong,._topologyNodeTitle_14kg9_140 span{min-width:0}._topologyNodeMeta_14kg9_156,._topologyNodeSubtle_14kg9_157{margin-top:6px;color:var(--text-secondary);font-family:var(--font-code);font-size:11px;line-height:1.4;overflow-wrap:anywhere}._topologyNodeSubtle_14kg9_157{color:var(--text-muted)}._topologyState_14kg9_170{margin-left:auto;flex:0 0 auto;border:1px solid var(--border);border-radius:var(--radius-pill);padding:2px 7px;background:color-mix(in srgb,var(--bg-card) 76%,transparent);color:var(--text-secondary);font-family:var(--font-label);font-size:10px;font-weight:600}._topologyEmpty_14kg9_183{min-height:82px;display:flex;align-items:center;justify-content:center;border:1px dashed var(--border);border-radius:8px;color:var(--text-muted);background:color-mix(in srgb,var(--bg-secondary) 58%,transparent);padding:12px;text-align:center;font-size:12px;line-height:1.45}._topologyOverflow_14kg9_198{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:34px;padding:6px 8px 6px 12px;border:1px solid var(--border);border-radius:7px;background:color-mix(in srgb,var(--bg-card) 72%,transparent);color:var(--text-secondary);font-family:var(--font-label);font-size:12px}._topologyOverflowButton_14kg9_213{flex:0 0 auto;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;font-family:var(--font-label);font-size:11px;font-weight:600;padding:4px 8px;transition:background var(--transition),border-color var(--transition),color var(--transition)}._topologyOverflowButton_14kg9_213:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent)}._topologyServerColumn_14kg9_236{min-width:0;display:flex;flex-direction:column;gap:10px}._topologyServer_14kg9_236{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:178px;border-color:color-mix(in srgb,var(--accent) 42%,var(--border));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 16%,transparent)}._topologyServerIcon_14kg9_254{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid var(--border-highlight);border-radius:50%;background:var(--accent-dim);color:var(--accent);margin-bottom:10px}._topologyServerBody_14kg9_267{display:flex;flex-direction:column;align-items:center;gap:8px;min-width:0;width:100%}._topologyServerTitle_14kg9_276{color:var(--text-primary);font-family:var(--font-label);font-size:15px;font-weight:700}._topologyServerMeta_14kg9_283{color:var(--text-secondary);font-family:var(--font-code);font-size:11px;overflow-wrap:anywhere}._routingSummaryCompact_14kg9_290{display:flex;justify-content:center;width:100%;min-width:0}._disabled_14kg9_298{opacity:.4;pointer-events:none}._cardHeader_14kg9_304{font-family:var(--font-label);font-weight:500;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);margin-bottom:12px;display:flex;align-items:center;justify-content:space-between}._cardHint_14kg9_317{margin:-4px 0 12px;color:var(--text-muted);font-size:12px;line-height:1.5}._clearButton_14kg9_324{border:1px solid var(--danger-border);background:var(--danger-bg);color:var(--danger-text);border-radius:var(--radius-control);padding:6px 12px;font-family:var(--font-label);font-size:12px;font-weight:600;cursor:pointer;transition:background var(--transition),border-color var(--transition),color var(--transition)}._clearButton_14kg9_324:hover{background:var(--danger-hover-bg);border-color:var(--danger)}._clearButton_14kg9_324:focus-visible{outline:none;box-shadow:var(--focus-ring)}._serverGrid_14kg9_348{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;font-family:var(--font-code);font-size:13px}._serverGrid_14kg9_348 dt{color:var(--text-muted)}._serverGrid_14kg9_348 dd{color:var(--text-primary);margin:0}._statusRow_14kg9_366{display:flex;align-items:center;gap:16px;margin-bottom:12px}._metaItem_14kg9_373{font-family:var(--font-code);font-size:12px;color:var(--text-secondary)}._table_14kg9_380{width:100%;border-collapse:collapse;font-family:var(--font-code);font-size:12px}._table_14kg9_380 th{text-align:left;color:var(--text-muted);font-weight:400;padding:4px 8px 4px 0;border-bottom:1px solid var(--border)}._table_14kg9_380 td{padding:6px 8px 6px 0;color:var(--text-primary)}._tableWrap_14kg9_400{overflow-x:auto}._table_14kg9_380 tr:hover td{background:var(--accent-dim)}._routingSummary_14kg9_290{display:inline-flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}._manageLink_14kg9_416{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-primary);font-family:var(--font-label);font-size:11px;font-weight:600;text-decoration:none;transition:border-color var(--transition),background var(--transition),color var(--transition)}._manageLink_14kg9_416:hover{border-color:var(--border-highlight);background:var(--accent-dim);color:var(--accent);text-decoration:none}._segment_14kg9_442,._segmentActive_14kg9_443{height:28px;padding:0 10px;border:none;border-right:1px solid var(--border);background:transparent;color:var(--text-secondary);font-family:var(--font-label);font-size:12px;cursor:pointer}._segment_14kg9_442:last-child,._segmentActive_14kg9_443:last-child{border-right:none}._segment_14kg9_442:hover:not(:disabled){background:var(--accent-dim);color:var(--accent)}._segmentActive_14kg9_443{background:var(--accent-dim);color:var(--text-primary);font-weight:600}._segment_14kg9_442:disabled,._segmentActive_14kg9_443:disabled{cursor:default;opacity:.55}._targetPrimary_14kg9_477{white-space:nowrap}._monoMuted_14kg9_481{color:var(--text-secondary)}._copyIconButton_14kg9_485{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-left:6px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;vertical-align:middle;transition:border-color var(--transition),background var(--transition),color var(--transition)}._copyIconButton_14kg9_485:hover{color:var(--accent);border-color:var(--border-highlight);background:var(--accent-dim)}._routingBadge_14kg9_510{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--border-highlight);border-radius:var(--radius-control);background:var(--accent-dim);color:var(--text-primary);font-family:var(--font-label);font-size:11px;font-weight:600}._studioStateBadge_14kg9_524{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--border);border-radius:var(--radius-control);background:var(--bg-secondary);color:var(--text-secondary);font-family:var(--font-label);font-size:11px;font-weight:600;white-space:nowrap}._studioState_running_14kg9_539{border-color:color-mix(in srgb,var(--success) 42%,var(--border));background:color-mix(in srgb,var(--success) 12%,var(--bg-secondary));color:var(--success)}._studioState_paused_14kg9_545{border-color:color-mix(in srgb,var(--warning) 42%,var(--border));background:color-mix(in srgb,var(--warning) 12%,var(--bg-secondary));color:var(--warning)}._studioState_edit_14kg9_551{border-color:var(--border-highlight);background:color-mix(in srgb,var(--accent) 9%,var(--bg-secondary));color:var(--text-primary)}._studioState_unknown_14kg9_557{border-color:var(--border);background:var(--bg-secondary);color:var(--text-muted)}._toggleBtn_14kg9_564{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:0 4px;transition:color var(--transition)}._toggleBtn_14kg9_564:hover{color:var(--accent)}._disconnected_14kg9_579{text-align:center;padding:32px 16px}._disconnected_14kg9_579 h3{color:var(--error);font-size:16px;margin:0 0 8px}._disconnected_14kg9_579 p{color:var(--text-secondary);font-size:13px;margin:0 0 4px}._disconnectedActions_14kg9_596{display:flex;gap:8px;justify-content:center;margin-top:16px}._btn_14kg9_603{font-family:var(--font-label);font-size:12px;padding:6px 14px;border-radius:var(--radius-control);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-primary);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._btn_14kg9_603:hover{border-color:var(--accent);background:var(--accent-dim)}._activity_active_14kg9_621,._activity_stale_14kg9_622,._activity_unknown_14kg9_623{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:middle}._activity_active_14kg9_621{background:var(--success);box-shadow:0 0 4px var(--success)}._activity_stale_14kg9_622{background:var(--text-muted)}._activity_unknown_14kg9_623{background:var(--text-muted);opacity:.4}._killBtn_14kg9_647{font-family:var(--font-label);font-size:11px;padding:3px 10px;border-radius:var(--radius-control);border:1px solid var(--danger-border);background:var(--danger-bg);color:var(--danger-text);cursor:pointer;transition:background var(--transition),border-color var(--transition)}._killBtn_14kg9_647:hover{background:var(--danger-hover-bg);border-color:var(--danger);color:var(--danger-text)}._killBtn_14kg9_647:focus-visible{outline:none;box-shadow:var(--focus-ring)}._emptyRow_14kg9_671{color:var(--text-muted);font-style:italic}@media(max-width:980px){._topologyHeader_14kg9_30{flex-direction:column;align-items:stretch}._topologyGrid_14kg9_74{grid-template-columns:1fr;gap:10px}._topologyColumnHeaderSpacer_14kg9_101{display:none}._topologyServer_14kg9_236{min-height:150px}}@media(max-width:640px){._card_14kg9_11,._topologyCard_14kg9_19{padding:14px}._topologyNodeTitle_14kg9_140{flex-wrap:wrap}._topologyState_14kg9_170{margin-left:0}}
@@ -0,0 +1,11 @@
1
+ import{i as tt,u as et,r as d,j as t,f as nt,a as U,D as st,L as it,M as ct,k as W,e as at,l as lt,s as rt}from"./index-CnXGGM07.js";import{I as p}from"./InfoLabel-BAhsgLcj.js";import{P as dt}from"./PageHeader-Bfy2f-GH.js";import{S as ot}from"./StatusBadge-Df9BQsJU.js";import{T as X}from"./TooltipText-CGH7dKN6.js";import{C as J}from"./ConfirmModal-BqCEvp7Y.js";import{u as gt,f as ut}from"./useLiveUptime-1Et9Q6mq.js";import{C as K}from"./copy-D-nSZB9j.js";import"./ConfirmModal.module-D1aZY2bQ.js";/**
2
+ * @license lucide-react v1.8.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const pt=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],ht=tt("bot",pt);/**
7
+ * @license lucide-react v1.8.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const yt=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],mt=tt("server",yt),xt="_container_1h084_2",_t="_entry_1h084_14",St="_timestamp_1h084_21",jt="_message_1h084_27",vt="_warn_1h084_34",kt="_error_1h084_39",ft="_empty_1h084_44",F={container:xt,entry:_t,timestamp:St,message:jt,warn:vt,error:kt,empty:ft};function Ct(e){const s=new Date(e);return Number.isNaN(s.getTime())?e:`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}`}function bt({entries:e}){const{t:s}=et(),n=d.useRef(null);return d.useEffect(()=>{const i=n.current;i&&(i.scrollTop=i.scrollHeight)},[e.length]),t.jsx("div",{ref:n,className:F.container,children:e.length===0?t.jsx("div",{className:F.empty,children:s("connection.log.empty","No events yet")}):e.map((i,r)=>t.jsxs("div",{className:`${F.entry} ${i.type?F[i.type]:""}`,children:[t.jsx("span",{className:F.timestamp,children:Ct(i.timestamp)}),t.jsx("span",{className:F.message,children:i.message})]},r))})}const Q=50;function wt(){const e=new Date;return`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}function Nt(){const{level:e,status:s,error:n}=nt(),[i,r]=d.useState(null),[y,g]=d.useState(null),[c,N]=d.useState([]),C=d.useRef(null),A=d.useCallback((u,j)=>{N(w=>{const S=[...w,{timestamp:wt(),message:u,type:j}];return S.length>Q?S.slice(-Q):S})},[]),m=d.useCallback(async()=>{try{const u=await U.get("/connection-info");r(u)}catch{r(null)}},[]),M=d.useCallback(async()=>{try{const u=await U.get("/api/dashboard/studio-routing");g(u)}catch{g(null)}},[]),I=d.useCallback(async u=>{const j=await U.patch("/api/dashboard/studio-routing",u);return g(j),await m(),j},[m]),$=d.useCallback(async()=>{try{const u=await U.get("/api/dashboard/connection-log");N(u.entries??[])}catch{N([])}},[]),H=d.useCallback(async()=>{await U.post("/api/dashboard/connection-log/clear"),N([])},[]),b=d.useCallback(async u=>{await U.post("/api/dashboard/kill-agent",{instanceId:u}),await m()},[m]);return d.useEffect(()=>{e!=="disconnected"&&s?(m(),M()):g(null),$()},[e,s,m,$,M]),d.useEffect(()=>{const u=new st;C.current=u,u.connect();const j=u.on("connection",S=>{const h=S;h.status!=="updated"&&h.clientId&&A(`Plugin ${h.status} — ${h.clientId}`,h.status==="disconnected"?"warn":"info"),m(),M()}),w=u.on("mcp_status",S=>{const h=S,z=h.status==="registered"?"registered":"unregistered";A(`MCP ${z} — ${h.aiClientName}`,h.status==="registered"?"info":"warn"),m(),M()});return()=>{j(),w(),u.disconnect(),C.current=null}},[A,m,M]),{status:s,connectionInfo:i,studioRouting:y,connectionLog:c,level:e,error:n,clearConnectionLog:H,killAgent:b,updateStudioRouting:I}}const It="_page_14kg9_2",Lt="_card_14kg9_11",At="_topologyCard_14kg9_19",Mt="_topologyDisconnected_14kg9_26",Pt="_topologyHeader_14kg9_30",Bt="_topologyIntro_14kg9_38",$t="_topologyNetwork_14kg9_45",Et="_topologyLinks_14kg9_49",Tt="_topologyLink_14kg9_49",Ht="_topologyLink_agent_14kg9_66",Dt="_topologyLink_studio_14kg9_70",Ot="_topologyGrid_14kg9_74",Ut="_topologyColumn_14kg9_83",Ft="_topologyColumnHeader_14kg9_90",zt="_topologyColumnHeaderSpacer_14kg9_101",Gt="_topologyCount_14kg9_105",Wt="_topologyList_14kg9_120",qt="_topologyListCentered_14kg9_128",Vt="_topologyNode_14kg9_132",Kt="_topologyNodeTitle_14kg9_140",Yt="_topologyNodeMeta_14kg9_156",Rt="_topologyNodeSubtle_14kg9_157",Xt="_topologyState_14kg9_170",Jt="_topologyEmpty_14kg9_183",Qt="_topologyOverflow_14kg9_198",Zt="_topologyOverflowButton_14kg9_213",te="_topologyServerColumn_14kg9_236",ee="_topologyServer_14kg9_236",oe="_topologyServerIcon_14kg9_254",ne="_topologyServerBody_14kg9_267",se="_topologyServerTitle_14kg9_276",ie="_topologyServerMeta_14kg9_283",ce="_routingSummaryCompact_14kg9_290",ae="_disabled_14kg9_298",le="_cardHeader_14kg9_304",re="_cardHint_14kg9_317",de="_clearButton_14kg9_324",ge="_serverGrid_14kg9_348",ue="_statusRow_14kg9_366",pe="_metaItem_14kg9_373",he="_table_14kg9_380",ye="_tableWrap_14kg9_400",me="_routingSummary_14kg9_290",xe="_manageLink_14kg9_416",_e="_segment_14kg9_442",Se="_segmentActive_14kg9_443",je="_targetPrimary_14kg9_477",ve="_monoMuted_14kg9_481",ke="_copyIconButton_14kg9_485",fe="_routingBadge_14kg9_510",Ce="_studioStateBadge_14kg9_524",be="_studioState_running_14kg9_539",we="_studioState_paused_14kg9_545",Ne="_studioState_edit_14kg9_551",Ie="_studioState_unknown_14kg9_557",Le="_toggleBtn_14kg9_564",Ae="_disconnected_14kg9_579",Me="_disconnectedActions_14kg9_596",Pe="_btn_14kg9_603",Be="_activity_active_14kg9_621",$e="_activity_stale_14kg9_622",Ee="_activity_unknown_14kg9_623",Te="_killBtn_14kg9_647",He="_emptyRow_14kg9_671",o={page:It,card:Lt,topologyCard:At,topologyDisconnected:Mt,topologyHeader:Pt,topologyIntro:Bt,topologyNetwork:$t,topologyLinks:Et,topologyLink:Tt,topologyLink_agent:Ht,topologyLink_studio:Dt,topologyGrid:Ot,topologyColumn:Ut,topologyColumnHeader:Ft,topologyColumnHeaderSpacer:zt,topologyCount:Gt,topologyList:Wt,topologyListCentered:qt,topologyNode:Vt,topologyNodeTitle:Kt,topologyNodeMeta:Yt,topologyNodeSubtle:Rt,topologyState:Xt,topologyEmpty:Jt,topologyOverflow:Qt,topologyOverflowButton:Zt,topologyServerColumn:te,topologyServer:ee,topologyServerIcon:oe,topologyServerBody:ne,topologyServerTitle:se,topologyServerMeta:ie,routingSummaryCompact:ce,disabled:ae,cardHeader:le,cardHint:re,clearButton:de,serverGrid:ge,statusRow:ue,metaItem:pe,table:he,tableWrap:ye,routingSummary:me,manageLink:xe,segment:_e,segmentActive:Se,targetPrimary:je,monoMuted:ve,copyIconButton:ke,routingBadge:fe,studioStateBadge:Ce,studioState_running:be,studioState_paused:we,studioState_edit:Ne,studioState_unknown:Ie,toggleBtn:Le,disconnected:Ae,disconnectedActions:Me,btn:Pe,activity_active:Be,activity_stale:$e,activity_unknown:Ee,killBtn:Te,emptyRow:He},V=5;function De(e){return e?Date.now()-e<3e4?"active":"stale":"unknown"}function Oe(e,s){return e==="active"?s("connection.topology.active","Active"):e==="stale"?s("connection.topology.stale","Stale"):s("connection.topology.unknown","Unknown")}function Ue(e){return e.length>10?e.slice(0,10):e}function Z(e,s){return e.replace("{count}",String(s))}function Fe(e,s,n){const i=e.studioState??"unknown",r={edit:s("connection.targets.studioState.edit","Edit"),running:s("connection.targets.studioState.running","Running"),paused:s("connection.targets.studioState.paused","Paused"),unknown:s("connection.targets.studioState.unknown","Unknown")},y=e.studioStateSource==="thread"?s("connection.targets.studioState.source.thread","WEPPY play command"):e.studioStateSource==="pluginConnection"?s("connection.targets.studioState.source.pluginConnection","Studio Play/Test connection"):e.studioStateSource==="runService"?s("connection.targets.studioState.source.runService","Studio RunService"):s("connection.targets.studioState.source.unknown","Unknown source"),g=e.studioStateUpdatedAt?n(e.studioStateUpdatedAt):s("connection.targets.studioState.updatedUnknown","not reported");return{state:i,label:r[i],tooltip:`${y} · ${g}`}}function ze(e,s){return e.length!==s.length?!1:e.every((n,i)=>{const r=s[i];return r!==void 0&&n.id===r.id&&n.side===r.side&&Math.abs(n.x1-r.x1)<.5&&Math.abs(n.y1-r.y1)<.5&&Math.abs(n.x2-r.x2)<.5&&Math.abs(n.y2-r.y2)<.5})}function f(e,s,n){return{x:s-e.left,y:n-e.top}}function Ge(e,s,n,i){if(s.right<=n.left){const g=f(i,s.right,s.top+s.height/2),c=f(i,n.left,n.top+n.height/2);return{id:e,side:"agent",x1:g.x,y1:g.y,x2:c.x,y2:c.y}}if(s.bottom<=n.top){const g=f(i,s.left+s.width/2,s.bottom),c=f(i,n.left+n.width/2,n.top);return{id:e,side:"agent",x1:g.x,y1:g.y,x2:c.x,y2:c.y}}const r=f(i,s.left+s.width/2,s.top),y=f(i,n.left+n.width/2,n.bottom);return{id:e,side:"agent",x1:r.x,y1:r.y,x2:y.x,y2:y.y}}function We(e,s,n,i){if(n.right<=s.left){const g=f(i,s.left,s.top+s.height/2),c=f(i,n.right,n.top+n.height/2);return{id:e,side:"studio",x1:g.x,y1:g.y,x2:c.x,y2:c.y}}if(n.bottom<=s.top){const g=f(i,s.left+s.width/2,s.top),c=f(i,n.left+n.width/2,n.bottom);return{id:e,side:"studio",x1:g.x,y1:g.y,x2:c.x,y2:c.y}}const r=f(i,s.left+s.width/2,s.bottom),y=f(i,n.left+n.width/2,n.top);return{id:e,side:"studio",x1:r.x,y1:r.y,x2:y.x,y2:y.y}}function qe({agents:e,isDisconnected:s,pinnedTargetClientId:n,priorityTarget:i,status:r,studioRoutingMode:y,studioTargets:g,t:c,timeAgo:N,onCopySelector:C,onManageRouting:A}){const[m,M]=d.useState(!1),[I,$]=d.useState(!1),[H,b]=d.useState([]),u=d.useRef(null),j=d.useRef(null),w=d.useRef(new Map),S=d.useRef(new Map),h=y==="pinned"?c("connection.routing.pinned","Manual: Pinned Studio"):c("connection.routing.recentPriority","Automatic: Recent priority"),z=s?"offline":"online",k=d.useMemo(()=>m?e:e.slice(0,V),[e,m]),D=Math.max(0,e.length-k.length),v=d.useMemo(()=>I?g:g.slice(0,V),[g,I]),E=Math.max(0,g.length-v.length),Y=[o.topologyList,k.length<=1?o.topologyListCentered:""].filter(Boolean).join(" "),R=[o.topologyList,v.length<=1?o.topologyListCentered:""].filter(Boolean).join(" "),O=d.useCallback(a=>x=>{if(x){w.current.set(a,x);return}w.current.delete(a)},[]),l=d.useCallback(a=>x=>{if(x){S.current.set(a,x);return}S.current.delete(a)},[]),L=d.useCallback(()=>{const a=u.current,x=j.current;if(!a||!x){b([]);return}const _=a.getBoundingClientRect(),P=x.getBoundingClientRect(),q=[];k.forEach(B=>{const G=w.current.get(B.instanceId);G&&q.push(Ge(`agent-${B.instanceId}`,G.getBoundingClientRect(),P,_))}),v.forEach(B=>{const G=S.current.get(B.clientId);G&&q.push(We(`studio-${B.clientId}`,G.getBoundingClientRect(),P,_))}),b(B=>ze(B,q)?B:q)},[k,v]);return d.useLayoutEffect(()=>{L();const a=[u.current,j.current,...k.map(_=>w.current.get(_.instanceId)),...v.map(_=>S.current.get(_.clientId))].filter(_=>_!=null);if(window.addEventListener("resize",L),typeof ResizeObserver>"u")return()=>{window.removeEventListener("resize",L)};const x=new ResizeObserver(L);return a.forEach(_=>x.observe(_)),()=>{window.removeEventListener("resize",L),x.disconnect()}},[L,k,v]),t.jsxs("section",{className:`${o.topologyCard} ${s?o.topologyDisconnected:""}`,"aria-label":c("connection.topology.ariaLabel","Connection topology"),children:[t.jsxs("div",{className:o.topologyHeader,children:[t.jsxs("div",{children:[t.jsx("div",{className:o.cardHeader,children:c("connection.topology.title","Connection topology")}),t.jsx("p",{className:o.topologyIntro,children:c("connection.topology.description","AI agents and Roblox Studio windows connect through one WEPPY MCP Server.")})]}),t.jsx(it,{to:"/controls?section=studio-routing",className:o.manageLink,onClick:A,children:c("connection.routing.manage","Manage routing")})]}),t.jsxs("div",{className:o.topologyNetwork,ref:u,children:[t.jsx("svg",{"aria-hidden":"true",className:o.topologyLinks,"data-testid":"topology-connection-lines",focusable:"false",children:H.map(a=>t.jsx("line",{className:`${o.topologyLink} ${o[`topologyLink_${a.side}`]}`,"data-side":a.side,vectorEffect:"non-scaling-stroke",x1:a.x1,x2:a.x2,y1:a.y1,y2:a.y2},a.id))}),t.jsxs("div",{className:o.topologyGrid,children:[t.jsxs("div",{className:o.topologyColumn,children:[t.jsxs("div",{className:o.topologyColumnHeader,children:[t.jsx(ht,{size:15,"aria-hidden":"true"}),t.jsx("span",{children:c("connection.agents.title","AI Agents")}),t.jsx("span",{className:o.topologyCount,children:e.length})]}),t.jsxs("div",{className:Y,children:[e.length>0?k.map(a=>{const x=De(a.lastSeen),_=a.aiClientName??Ue(a.instanceId),P=a.lastSeen??a.lastCommandAt??a.connectedAt;return t.jsxs("div",{className:o.topologyNode,ref:O(a.instanceId),children:[t.jsxs("div",{className:o.topologyNodeTitle,children:[t.jsx("span",{className:o[`activity_${x}`]}),t.jsx("strong",{children:_}),t.jsx("span",{className:o.topologyState,children:Oe(x,c)})]}),t.jsx("div",{className:o.topologyNodeMeta,children:P?`${c("connection.topology.lastActivity","Last activity")} ${N(P)}`:c("connection.topology.noActivity","No recent activity")})]},a.instanceId)}):t.jsx("div",{className:o.topologyEmpty,children:c("connection.agents.none","No agents connected")}),e.length>V?t.jsxs("div",{className:o.topologyOverflow,children:[D>0?t.jsx("span",{children:Z(c("connection.topology.moreAgents","+{count} more agents"),D)}):t.jsx("span",{children:c("connection.topology.allAgentsVisible","All agents visible")}),t.jsx("button",{type:"button",className:o.topologyOverflowButton,"aria-label":m?c("connection.topology.showLessAgents","Show less AI agents"):c("connection.topology.showAllAgents","Show all AI agents"),onClick:()=>M(a=>!a),children:m?c("connection.topology.showLess","Show less"):c("connection.topology.showAll","Show all")})]}):null]})]}),t.jsxs("div",{className:o.topologyServerColumn,children:[t.jsx("div",{className:o.topologyColumnHeaderSpacer,"aria-hidden":"true"}),t.jsxs("div",{className:`${o.topologyNode} ${o.topologyServer}`,ref:j,children:[t.jsx("div",{className:o.topologyServerIcon,children:t.jsx(mt,{size:18,"aria-hidden":"true"})}),t.jsxs("div",{className:o.topologyServerBody,children:[t.jsx("div",{className:o.topologyServerTitle,children:c("connection.topology.serverTitle","MCP Server")}),t.jsx(ot,{status:z}),t.jsxs("div",{className:o.topologyServerMeta,children:[r!=null&&r.version?`v${r.version}`:c("connection.topology.versionUnknown","Version unknown"),r!=null&&r.sessionId?` · ${c("connection.server.session","Session")} ${r.sessionId.slice(0,8)}`:""]}),t.jsx("div",{className:o.routingSummaryCompact,children:t.jsx("span",{className:o.routingBadge,children:h})})]})]})]}),t.jsxs("div",{className:o.topologyColumn,children:[t.jsxs("div",{className:o.topologyColumnHeader,children:[t.jsx(ct,{size:15,"aria-hidden":"true"}),t.jsx("span",{children:c("connection.targets.title","Studio Targets")}),t.jsx("span",{className:o.topologyCount,children:g.length})]}),t.jsxs("div",{className:R,children:[g.length>0?v.map(a=>{const x=y==="pinned"&&n===a.clientId,_=y==="recentPriority"&&(i==null?void 0:i.clientId)===a.clientId,P=Fe(a,c,N);return t.jsxs("div",{className:o.topologyNode,ref:l(a.clientId),children:[t.jsxs("div",{className:o.topologyNodeTitle,children:[t.jsx("span",{className:o.targetPrimary,children:a.targetAlias}),t.jsx(W,{text:c("connection.targets.copyTargetAlias","Copy Studio ID"),children:t.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":c("connection.targets.copyTargetAlias","Copy Studio ID"),onClick:()=>C(a.targetAlias,"target_alias"),children:t.jsx(K,{size:13,"aria-hidden":"true"})})}),x?t.jsx("span",{className:o.routingBadge,children:c("connection.routing.pinnedBadge","Pinned")}):_?t.jsx("span",{className:o.routingBadge,children:c("connection.routing.priorityBadge","Priority")}):null,t.jsx(W,{text:P.tooltip,children:t.jsx("span",{className:`${o.studioStateBadge} ${o[`studioState_${P.state}`]}`,children:P.label})})]}),t.jsxs("div",{className:o.topologyNodeMeta,children:[t.jsx("span",{children:a.placeName??c("connection.topology.placeUnknown","Place unknown")}),a.placeId!==void 0?` · ${a.placeId}`:""]}),t.jsxs("div",{className:o.topologyNodeSubtle,children:[a.connectionState," · ",c("connection.targets.lastSeen","Last Seen")," ",N(a.lastSeen)]})]},a.clientId)}):t.jsx("div",{className:o.topologyEmpty,children:c("connection.targets.none","No Studio targets connected. Open Roblox Studio and connect WEPPY Plugin.")}),g.length>V?t.jsxs("div",{className:o.topologyOverflow,children:[E>0?t.jsx("span",{children:Z(c("connection.topology.moreStudios","+{count} more studios"),E)}):t.jsx("span",{children:c("connection.topology.allStudiosVisible","All studios visible")}),t.jsx("button",{type:"button",className:o.topologyOverflowButton,"aria-label":I?c("connection.topology.showLessStudios","Show less Studio targets"):c("connection.topology.showAllStudios","Show all Studio targets"),onClick:()=>$(a=>!a),children:I?c("connection.topology.showLess","Show less"):c("connection.topology.showAll","Show all")})]}):null]})]})]})]})]})}function T(e,s){const n=Math.max(0,Math.floor((Date.now()-e)/1e3));return n<60?`${n}${s("connection.time.secondsAgo","s ago")}`:n<3600?`${Math.floor(n/60)}${s("connection.time.minutesAgo","m ago")}`:`${Math.floor(n/3600)}${s("connection.time.hoursAgo","h ago")}`}function Ve(e){return e?Date.now()-e<3e4?"active":"stale":"unknown"}function Ke(e,s){const n=e.studioState??"unknown",i={edit:s("connection.targets.studioState.edit","Edit"),running:s("connection.targets.studioState.running","Running"),paused:s("connection.targets.studioState.paused","Paused"),unknown:s("connection.targets.studioState.unknown","Unknown")},r=e.studioStateSource==="thread"?s("connection.targets.studioState.source.thread","WEPPY play command"):e.studioStateSource==="pluginConnection"?s("connection.targets.studioState.source.pluginConnection","Studio Play/Test connection"):e.studioStateSource==="runService"?s("connection.targets.studioState.source.runService","Studio RunService"):s("connection.targets.studioState.source.unknown","Unknown source"),y=e.studioStateUpdatedAt?T(e.studioStateUpdatedAt,s):s("connection.targets.studioState.updatedUnknown","not reported"),g=e.playtestMode&&e.playtestMode!=="unknown"?` · ${e.playtestMode}`:"";return{state:n,label:`${i[n]}${g}`,tooltip:`${r} · ${y}`}}function no(){const{t:e}=et(),{trackEvent:s}=at(),{status:n,connectionInfo:i,studioRouting:r,connectionLog:y,level:g,clearConnectionLog:c,killAgent:N}=Nt(),{show:C}=lt(),[A,m]=d.useState(!0),[M,I]=d.useState(!1),[$,H]=d.useState(!1),[b,u]=d.useState(null),[j,w]=d.useState(!1),S=gt(n==null?void 0:n.uptime),h=g==="disconnected",z=h?"offline":"online",k=(r==null?void 0:r.studioRoutingMode)??(n==null?void 0:n.studioRoutingMode)??"recentPriority",D=(r==null?void 0:r.pinnedTargetClientId)??(n==null?void 0:n.pinnedTargetClientId)??null,v=rt((r==null?void 0:r.targets)??(n==null?void 0:n.pluginClients)??[],k,D),E=(r==null?void 0:r.priorityTarget)??v[0],Y=async()=>{if(b){w(!0);try{await N(b.instanceId),C(e("connection.agents.killed","Agent killed"),"success"),u(null)}catch{C(e("connection.agents.killFailed","Failed to kill agent"),"error")}finally{w(!1)}}},R=async()=>{H(!0);try{await c(),C(e("toast.clearSuccess","Cleared successfully"),"success"),I(!1)}catch{C(e("toast.clearFailed","Failed to clear data"),"error")}finally{H(!1)}},O=async(l,L)=>{try{await navigator.clipboard.writeText(l),C(e("connection.targets.copied","Copied value"),"success"),s("dashboard_click_event",{click_target:`connection_copy_${L}`,page:"connection"})}catch{C(e("connection.targets.copyFailed","Failed to copy value"),"error")}};return t.jsxs("div",{className:o.page,children:[t.jsx(dt,{title:e("page.connection.title","Connection"),description:e("page.connection.description","Inspect MCP server, AI agent, Studio plugin, and connection log status."),helpTopicId:"connection",helpState:{connectionLevel:g}}),t.jsx(qe,{agents:(i==null?void 0:i.mcpInstances)??[],isDisconnected:h,pinnedTargetClientId:D,priorityTarget:E,status:n??null,studioRoutingMode:k,studioTargets:v,t:e,timeAgo:l=>T(l,e),onCopySelector:O,onManageRouting:()=>s("dashboard_click_event",{click_target:"connection_manage_routing",page:"connection"})}),t.jsxs("div",{className:o.card,children:[t.jsx("div",{className:o.cardHeader,children:e("connection.server.title","Server Status")}),h?t.jsxs("div",{className:o.disconnected,children:[t.jsx("h3",{children:e("level.l0.title")}),t.jsx("p",{children:e("level.l0.message")}),t.jsx("p",{children:e("common.reconnecting")}),t.jsxs("div",{className:o.disconnectedActions,children:[t.jsx("button",{className:o.btn,onClick:()=>window.location.reload(),children:e("connection.reconnect","Reconnect")}),t.jsx("button",{className:o.btn,onClick:()=>{window.location.hash="#/settings"},children:e("connection.checkSettings","Check Settings")})]})]}):t.jsxs(t.Fragment,{children:[t.jsx("div",{className:o.statusRow,children:t.jsx(ot,{status:z})}),t.jsxs("dl",{className:o.serverGrid,children:[(n==null?void 0:n.version)&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:t.jsx(p,{label:e("connection.server.version","Version"),tooltip:e("connection.server.version.tooltip","Installed MCP server version")})}),t.jsx("dd",{children:t.jsx(X,{text:e("connection.server.version.tooltip","Installed MCP server version"),children:`v${n.version}`})})]}),(n==null?void 0:n.pid)!=null&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:t.jsx(p,{label:e("connection.server.pid","PID"),tooltip:e("connection.server.pid.tooltip","Operating system process identifier")})}),t.jsx("dd",{children:n.pid})]}),(n==null?void 0:n.uptime)!=null&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:t.jsx(p,{label:e("connection.server.uptime","Uptime"),tooltip:e("connection.server.uptime.tooltip","Time elapsed since the MCP server started")})}),t.jsx("dd",{children:ut(S??n.uptime)})]}),(n==null?void 0:n.sessionId)&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:t.jsx(p,{label:e("connection.server.session","Session"),tooltip:e("connection.server.session.tooltip","Current MCP session identifier")})}),t.jsx("dd",{children:n.sessionId.slice(0,8)})]}),(i==null?void 0:i.serverExecutable)&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{children:t.jsx(p,{label:e("connection.server.exec","Exec"),tooltip:e("connection.server.exec.tooltip","Executable path used to launch the MCP server")})}),t.jsx("dd",{children:i.serverExecutable})]})]})]})]}),t.jsxs("div",{className:`${o.card} ${h?o.disabled:""}`,children:[t.jsxs("div",{className:o.cardHeader,children:[t.jsxs("span",{children:[e("connection.agents.title","AI Agents")," ","(",(i==null?void 0:i.mcpInstanceCount)??0,")"]}),t.jsx("button",{className:o.toggleBtn,onClick:()=>m(l=>!l),"aria-label":A?e("common.collapse","Collapse"):e("common.expand","Expand"),children:A?"▾":"▸"})]}),A&&t.jsxs("table",{className:o.table,children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx("th",{children:e("connection.agents.name","Agent")}),t.jsx("th",{children:t.jsx(p,{label:e("connection.server.pid","PID"),tooltip:e("connection.server.pid.tooltip","Operating system process identifier")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.agents.projectRoot","Project Root"),tooltip:e("connection.agents.projectRoot.tooltip","Authoritative project root for sync ownership")})}),t.jsx("th",{children:e("connection.agents.connected","Connected")}),t.jsx("th",{children:t.jsx(p,{label:e("connection.agents.lastSeen","Last Seen"),tooltip:e("connection.agents.lastSeen.tooltip","Most recent heartbeat or activity from this agent")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.agents.lastCommand","Last Command"),tooltip:e("connection.agents.lastCommand.tooltip","Most recent tool call executed by this agent")})}),t.jsx("th",{})]})}),t.jsx("tbody",{children:i!=null&&i.mcpInstances&&i.mcpInstances.length>0?i.mcpInstances.map(l=>t.jsxs("tr",{children:[t.jsxs("td",{children:[t.jsx("span",{className:o[`activity_${Ve(l.lastSeen)}`]}),l.aiClientName??e("connection.agents.unknown","Unknown")]}),t.jsx("td",{children:l.pid}),t.jsx("td",{children:l.projectRoot??l.cwd??e("connection.agents.projectRoot.unresolved","Unresolved")}),t.jsx("td",{children:T(l.connectedAt,e)}),t.jsx("td",{children:l.lastSeen?T(l.lastSeen,e):"-"}),t.jsx("td",{children:l.lastCommandAt?T(l.lastCommandAt,e):"-"}),t.jsx("td",{children:!l.isServer&&t.jsx("button",{className:o.killBtn,onClick:()=>{s("dashboard_click_event",{click_target:"connection_kill_agent",page:"connection"}),u({instanceId:l.instanceId,name:l.aiClientName??l.instanceId.slice(0,8)})},children:e("connection.agents.kill","Kill")})})]},l.instanceId)):t.jsx("tr",{children:t.jsx("td",{colSpan:7,className:o.emptyRow,children:e("connection.agents.none","No agents connected")})})})]})]}),t.jsxs("div",{className:`${o.card} ${h?o.disabled:""}`,children:[t.jsxs("div",{className:o.cardHeader,children:[e("connection.targets.title","Studio Targets")," ","(",v.length,")"]}),t.jsx("p",{className:o.cardHint,children:e("connection.targets.help","When multiple Studio windows are connected, tell the agent to use Studio ID studio-1 to choose one.")}),t.jsx("div",{className:o.tableWrap,children:t.jsxs("table",{className:o.table,children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.target","Studio ID"),tooltip:e("connection.targets.target.tooltip","Short name for this Roblox Studio window")})}),t.jsx("th",{children:e("connection.targets.place","Place")}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.placeId","Place ID"),tooltip:e("connection.targets.placeId.tooltip","Roblox Place ID for this Studio window")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.clientId","Connection ID"),tooltip:e("connection.targets.clientId.tooltip","Full connection ID for diagnostics. Usually use Studio ID instead.")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.studioState","Studio State"),tooltip:e("connection.targets.studioState.tooltip","Current edit/play runtime state reported by this Studio window")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.session","Session"),tooltip:e("connection.targets.session.tooltip","Command channel state for this Studio target")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.lastUsed","Last Used"),tooltip:e("connection.targets.lastUsed.tooltip","Most recent plugin-route request routed to this Studio target")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.lastSeen","Last Seen"),tooltip:e("connection.targets.lastSeen.tooltip","Most recent heartbeat received from this Studio target")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.version","Version"),tooltip:e("connection.targets.version.tooltip","Installed plugin version reported by Studio")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.routing","Routing"),tooltip:e("connection.targets.routing.tooltip","Routing priority for requests without a named Studio target")})}),t.jsx("th",{children:t.jsx(p,{label:e("connection.targets.inFlight","In Flight"),tooltip:e("connection.targets.inFlight.tooltip","Active command request currently routed to this Studio target")})})]})}),t.jsx("tbody",{children:v.length>0?v.map(l=>{const L=l.clientId.slice(0,10),a=Ke(l,e);return t.jsxs("tr",{children:[t.jsxs("td",{children:[t.jsx("span",{className:o.monoMuted,title:l.clientId,children:l.targetAlias}),t.jsx(W,{text:e("connection.targets.copyTargetAlias","Copy Studio ID"),children:t.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":e("connection.targets.copyTargetAlias","Copy Studio ID"),onClick:()=>O(l.targetAlias,"target_alias"),children:t.jsx(K,{size:13,"aria-hidden":"true"})})})]}),t.jsx("td",{children:t.jsx("span",{className:o.targetPrimary,children:l.placeName??"-"})}),t.jsxs("td",{children:[l.placeId??"-",l.placeId!==void 0?t.jsx(W,{text:e("connection.targets.copyPlaceId","Copy Place ID"),children:t.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":e("connection.targets.copyPlaceId","Copy Place ID"),onClick:()=>O(String(l.placeId),"place_id"),children:t.jsx(K,{size:13,"aria-hidden":"true"})})}):null]}),t.jsxs("td",{children:[t.jsx("span",{className:o.monoMuted,title:l.clientId,children:L}),t.jsx(W,{text:e("connection.targets.copyClientId","Copy Connection ID"),children:t.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":e("connection.targets.copyClientId","Copy Connection ID"),onClick:()=>O(l.clientId,"client_id"),children:t.jsx(K,{size:13,"aria-hidden":"true"})})})]}),t.jsx("td",{children:t.jsx(X,{text:a.tooltip,children:t.jsx("span",{className:`${o.studioStateBadge} ${o[`studioState_${a.state}`]}`,children:a.label})})}),t.jsx("td",{children:l.connectionState}),t.jsx("td",{children:l.lastRoutedAt?T(l.lastRoutedAt,e):"-"}),t.jsx("td",{children:T(l.lastSeen,e)}),t.jsx("td",{children:l.pluginVersion??"-"}),t.jsx("td",{children:k==="pinned"&&D===l.clientId?t.jsx("span",{className:o.routingBadge,children:e("connection.routing.pinnedBadge","Pinned")}):k==="recentPriority"&&(E==null?void 0:E.clientId)===l.clientId?t.jsx("span",{className:o.routingBadge,children:e("connection.routing.priorityBadge","Priority")}):t.jsx("span",{className:o.monoMuted,children:"-"})}),t.jsx("td",{children:l.inFlightRequestId?l.inFlightRequestId.slice(0,8):"-"})]},l.clientId)}):t.jsx("tr",{children:t.jsx("td",{colSpan:11,className:o.emptyRow,children:e("connection.targets.none","No Studio targets connected. Open Roblox Studio and connect WEPPY Plugin.")})})})]})})]}),t.jsxs("div",{className:`${o.card} ${h?o.disabled:""}`,children:[t.jsxs("div",{className:o.cardHeader,children:[t.jsx("span",{children:e("connection.log.title","Connection Log")}),t.jsx("button",{className:o.clearButton,onClick:()=>{s("dashboard_click_event",{click_target:"connection_clear_log",page:"connection"}),I(!0)},children:e("common.clear","Clear")})]}),t.jsx(bt,{entries:y})]}),t.jsx(J,{open:M,title:e("connection.clear.title","Clear connection log?"),message:e("connection.clear.message","This permanently removes the stored connection log for the current project."),cancelLabel:e("common.cancel","Cancel"),confirmLabel:e("common.clear","Clear"),loading:$,onCancel:()=>!$&&I(!1),onConfirm:R}),t.jsx(J,{open:!!b,title:e("connection.agents.kill.title","Kill agent?"),message:`"${b==null?void 0:b.name}" 프로세스를 강제 종료합니다. 해당 에이전트의 진행 중인 작업이 중단됩니다.`,cancelLabel:e("common.cancel","Cancel"),confirmLabel:e("connection.agents.kill","Kill"),loading:j,onCancel:()=>!j&&u(null),onConfirm:Y})]})}export{no as Component};
@@ -1 +1 @@
1
- import{u as T,j as e,f as W,l as q,d as _,r,v as z,w as Q,x as X,a as H,s as K,y as Z,k as A,N as J}from"./index-BDJHcdyQ.js";import{P as ee}from"./PageHeader-B0qiATU4.js";import{I as N}from"./InfoLabel-BUXacsTE.js";import{s as g}from"./ConfirmModal.module-D1aZY2bQ.js";import{T as B}from"./TooltipText-DaLR7eg1.js";import{s as o,u as te}from"./useSettings-BJSPSJ0b.js";import{C as M}from"./copy-0T6g5IWT.js";function k(n,a){return e.jsxs("div",{className:g.pathBlock,children:[e.jsx("span",{className:g.pathLabel,children:n}),e.jsx("code",{className:g.pathCode,children:a})]})}function oe(n){const t=/^[A-Z]:\\/i.test(n)||n.includes("\\")?"\\":"/";return`${n.replace(/[\\/]+$/,"")}${t}weppy-project-sync`}function ne({open:n,step:a,selectedProjectRoot:t,studioConnected:c,loading:d=!1,errorMessage:p=null,onClose:s,onPick:h,onApply:j}){const{t:l}=T();if(!n)return null;const S=t?oe(t):"";return e.jsx("div",{className:g.backdrop,onClick:d?void 0:s,role:"presentation",children:e.jsxs("div",{className:g.modal,onClick:y=>y.stopPropagation(),role:"dialog","aria-modal":"true","aria-labelledby":"project-root-change-modal-title",children:[e.jsx("h2",{id:"project-root-change-modal-title",className:g.title,children:a==="initial"?l("header.projectRootModal.initial.title","Change project root"):l("header.projectRootModal.confirm.title","Confirm new project root")}),e.jsx("p",{className:g.message,children:a==="initial"?c?l("header.projectRootModal.initial.body.connected","MCP will switch to the new project root and resync current Studio contents into the new target."):l("header.projectRootModal.initial.body.disconnected","MCP will switch to the new project root and use the new folder as the next sync target."):l("header.projectRootModal.confirm.body","Review the selected project folder before applying.")}),e.jsxs("div",{className:g.bodyGrid,children:[a==="initial"?e.jsxs(e.Fragment,{children:[k(l("header.projectRootModal.initial.nextSyncRoot","New sync target after selection"),l("header.projectRootModal.initial.nextSyncRoot.placeholder","<selected project folder>/weppy-project-sync")),e.jsxs("ul",{className:g.warningList,children:[c?e.jsxs(e.Fragment,{children:[e.jsx("li",{children:l("header.projectRootModal.initial.warningStop","Current sync stops immediately.")}),e.jsx("li",{children:l("header.projectRootModal.initial.warningFreshSync","The current Studio contents will be used to build a fresh full sync in the new target.")})]}):e.jsx("li",{children:l("header.projectRootModal.initial.warningDeferredSync","If Studio is not connected, full resync starts the next time the plugin connects.")}),e.jsx("li",{children:l("header.projectRootModal.initial.warningNoMove","Old sync folders are not moved automatically.")})]})]}):e.jsxs(e.Fragment,{children:[k(l("header.projectRootModal.confirm.projectRoot","Selected project folder"),t??""),k(l("header.projectRootModal.confirm.syncRoot","New sync target"),S),e.jsx("p",{className:g.message,children:l("header.projectRootModal.confirm.warningNoMove","Existing sync folders are not moved automatically.")})]}),p?e.jsx("p",{className:`${g.message} ${g.errorMessage}`,children:p}):null]}),e.jsxs("div",{className:g.actions,children:[e.jsx("button",{className:g.cancelButton,onClick:s,disabled:d,children:l("header.projectRootModal.cancel","Cancel")}),a==="initial"?e.jsx("button",{className:g.confirmButton,onClick:h,disabled:d,children:d?"...":l("header.projectRootModal.pick","Choose folder")}):e.jsx("button",{className:g.confirmButton,onClick:j,disabled:d||!t,children:d?"...":l("header.projectRootModal.apply","Apply change")})]})]})})}function F(n,a){if(n&&typeof n=="object"&&"message"in n&&typeof n.message=="string"){const t=n.message.trim();if(t.length>0)return t}return a}function se(){const{level:n,status:a}=W(),{t}=T(),{show:c}=q(),{search:d}=_(),p=r.useRef(null),[s,h]=r.useState(null),[j,l]=r.useState(!1),[S,y]=r.useState(null),[m,R]=r.useState(null),[f,v]=r.useState(!1),[w,L]=r.useState(!1),[I,x]=r.useState(null),i=r.useMemo(()=>new URLSearchParams(d).get("section")==="project-root",[d]),C=r.useCallback(async()=>{if(n==="disconnected"){h(null),l(!1);return}l(!1);try{const u=await z();h(u)}catch{h(null),l(!0)}},[n]);r.useEffect(()=>{C()},[C,a==null?void 0:a.connectedClients,a==null?void 0:a.sessionId]),r.useEffect(()=>{var u,P,O;i&&((P=(u=p.current)==null?void 0:u.scrollIntoView)==null||P.call(u,{block:"start",behavior:"smooth"}),(O=p.current)==null||O.focus())},[i]);const b=(u=!1)=>{!u&&(f||w)||(y(null),R(null),x(null))},E=()=>{n==="disconnected"||!s||(x(null),R(null),y("initial"))},Y=async()=>{v(!0),x(null);try{const u=await X();if(u.cancelled||!u.projectRoot){b(!0);return}R(u.projectRoot),y("confirm")}catch(u){x(F(u,t("header.projectRootModal.error","Failed to change project root")))}finally{v(!1)}},G=async()=>{if(m){L(!0),x(null);try{const u=await Q(m);h(u),l(!1),b(!0)}catch(u){const P=F(u,t("header.projectRootModal.error","Failed to change project root"));x(P),c(P,"error")}finally{L(!1)}}},$=j?t("controls.projectRoot.unavailable","Project root unavailable"):t("common.loading","Loading..."),V=n==="disconnected"||!s;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{id:"controls-project-root",ref:p,tabIndex:-1,className:o.card,children:[e.jsxs("div",{className:o.cardHeader,children:[e.jsx(N,{label:t("controls.projectRoot.title","Project Root"),tooltip:t("controls.projectRoot.title.tooltip","Authoritative project root and sync target used by MCP.")}),e.jsx(B,{text:t("controls.projectRoot.live.tooltip","Changing this updates MCP runtime state immediately after confirmation."),children:e.jsx("span",{className:`${o.headerBadge} ${o.headerBadgeLive}`,children:t("settings.general.liveApply","Live Apply")})})]}),e.jsxs("dl",{className:o.controlGrid,children:[e.jsx("dt",{children:t("controls.projectRoot.projectRoot","Project Root")}),e.jsx("dd",{children:(s==null?void 0:s.projectRoot)??$}),e.jsx("dt",{children:t("controls.projectRoot.syncRoot","Sync Root")}),e.jsx("dd",{children:(s==null?void 0:s.projectSyncRoot)??$})]}),e.jsx("p",{className:o.controlHint,children:t("controls.projectRoot.hint","Use this only when MCP should write sync data under a different project folder. Existing sync folders are not moved automatically.")}),e.jsx("button",{type:"button",className:o.actionBtn,disabled:V,onClick:E,children:t("header.changeProjectRoot","Change Project Root")})]}),e.jsx(ne,{open:S!==null,step:S??"initial",selectedProjectRoot:m,studioConnected:n==="studioConnected",loading:f||w,errorMessage:I,onClose:b,onPick:Y,onApply:G})]})}function ie(n){if(!n)return null;const a=n.placeName?n.placeId!==void 0?`${n.placeName} · ${n.placeId}`:n.placeName:n.placeId!==void 0?String(n.placeId):null;return a?`${n.targetAlias} · ${a}`:n.targetAlias}function U(n,a){const t=Math.max(0,Math.floor((Date.now()-n)/1e3));return t<60?`${t}${a("connection.time.secondsAgo","s ago")}`:t<3600?`${Math.floor(t/60)}${a("connection.time.minutesAgo","m ago")}`:`${Math.floor(t/3600)}${a("connection.time.hoursAgo","h ago")}`}function ae(){const{status:n,level:a}=W(),{t}=T(),{show:c}=q(),{search:d}=_(),p=r.useRef(null),[s,h]=r.useState(null),[j,l]=r.useState(null),S=r.useMemo(()=>new URLSearchParams(d).get("section")==="studio-routing",[d]),y=r.useCallback(async()=>{if(a==="disconnected"){h(null);return}try{const i=await H.get("/api/dashboard/studio-routing");h(i)}catch{h(null)}},[a]);r.useEffect(()=>{y()},[y,n==null?void 0:n.connectedClients,n==null?void 0:n.sessionId]),r.useEffect(()=>{var i,C,b;S&&((C=(i=p.current)==null?void 0:i.scrollIntoView)==null||C.call(i,{block:"start",behavior:"smooth"}),(b=p.current)==null||b.focus())},[S]);const m=(s==null?void 0:s.studioRoutingMode)??(n==null?void 0:n.studioRoutingMode)??"recentPriority",R=(s==null?void 0:s.pinnedTargetClientId)??(n==null?void 0:n.pinnedTargetClientId)??null,f=K((s==null?void 0:s.targets)??(n==null?void 0:n.pluginClients)??[],m,R),v=(s==null?void 0:s.priorityTarget)??Z(f,m,R),w=ie(v),L=new Set(f.filter(i=>i.placeId!==void 0).map(i=>i.placeId).filter((i,C,b)=>b.filter(E=>E===i).length>1)),I=async i=>{l(i.studioRoutingMode==="pinned"?i.pinnedTargetClientId??"pinned":"recentPriority");try{const C=await H.patch("/api/dashboard/studio-routing",i);h(C)}catch{c(t("connection.routing.updateFailed","Failed to update routing target"),"error")}finally{l(null)}},x=async i=>{try{await navigator.clipboard.writeText(i),c(t("connection.targets.copied","Copied value"),"success")}catch{c(t("connection.targets.copyFailed","Failed to copy value"),"error")}};return e.jsxs("div",{id:"controls-studio-routing",ref:p,tabIndex:-1,className:o.card,children:[e.jsx("div",{className:o.cardHeader,children:e.jsx(N,{label:t("controls.studioRouting.title","Studio Routing"),tooltip:t("controls.studioRouting.title.tooltip","Routing priority for MCP requests that do not name a Studio target.")})}),e.jsxs("div",{className:o.routingOverview,children:[e.jsxs("div",{className:o.routingOverviewCopy,children:[e.jsx("span",{className:o.routingEyebrow,children:t("controls.studioRouting.priorityTitle","Priority for requests without a named Studio target")}),e.jsx("strong",{children:m==="pinned"?t("connection.routing.pinned","Manual: Pinned Studio"):t("connection.routing.recentPriority","Automatic: Recent priority")}),e.jsx("p",{children:t("controls.studioRouting.priorityDescription","Explicit Studio ID, Connection ID, or Place ID requests bypass this priority setting and route to the named Studio.")})]}),e.jsxs("div",{className:o.priorityTargetSummary,children:[e.jsx("span",{children:t("controls.studioRouting.currentPriorityTarget","Current priority target")}),e.jsx("strong",{children:w??t("controls.studioRouting.noPriorityTarget","No connected Studio target")})]})]}),e.jsxs("div",{className:o.studioRoutingChoiceControl,role:"group","aria-label":t("connection.routing.priorityControl","Priority mode for requests without a named Studio target"),children:[e.jsxs("button",{type:"button",className:m==="recentPriority"?o.segmentActive:o.segment,disabled:j!==null,"aria-pressed":m==="recentPriority",onClick:()=>I({studioRoutingMode:"recentPriority"}),children:[e.jsx("span",{children:t("connection.routing.recentPriority","Automatic: Recent priority")}),e.jsx("small",{children:t("controls.studioRouting.recentPriorityHelp","Requests the highest-priority active Studio, based on recent routed commands and connection order.")})]}),e.jsxs("button",{type:"button",className:m==="pinned"?o.segmentActive:o.segment,disabled:!f.length||j!==null,"aria-pressed":m==="pinned",onClick:()=>I({studioRoutingMode:"pinned"}),children:[e.jsx("span",{children:t("connection.routing.pinned","Manual: Pinned Studio")}),e.jsx("small",{children:t("controls.studioRouting.pinnedHelp","Requests the pinned Studio unless the agent names a Studio ID, Connection ID, or Place ID.")})]})]}),L.size>0?e.jsx("p",{className:o.routingWarning,children:t("controls.studioRouting.duplicatePlaceWarning","More than one connected Studio window has the same Place ID. Ask the AI agent to use Studio ID for that place.")}):null,e.jsx("div",{className:o.tableWrap,children:e.jsxs("table",{className:o.table,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:t("connection.targets.routing","Routing")}),e.jsx("th",{children:t("connection.targets.target","Studio ID")}),e.jsx("th",{children:t("connection.targets.place","Place")}),e.jsx("th",{children:t("connection.targets.placeId","Place ID")}),e.jsx("th",{children:t("connection.targets.lastUsed","Last Used")}),e.jsx("th",{children:t("connection.targets.lastSeen","Last Seen")}),e.jsx("th",{children:t("connection.targets.clientId","Connection ID")})]})}),e.jsx("tbody",{children:f.length>0?f.map(i=>e.jsxs("tr",{children:[e.jsx("td",{children:m==="pinned"&&R===i.clientId?e.jsx("span",{className:o.routingBadge,children:t("connection.routing.pinnedBadge","Pinned")}):m==="recentPriority"&&(v==null?void 0:v.clientId)===i.clientId?e.jsx("span",{className:o.routingBadge,children:t("connection.routing.priorityBadge","Priority")}):m==="pinned"?e.jsx("button",{type:"button",className:o.setPriorityTargetButton,disabled:j!==null,onClick:()=>I({studioRoutingMode:"pinned",pinnedTargetClientId:i.clientId}),children:t("connection.routing.setPriorityTarget","Set as priority target")}):null}),e.jsxs("td",{children:[e.jsx("span",{className:o.monoMuted,title:i.clientId,children:i.targetAlias}),e.jsx(A,{text:t("connection.targets.copyTargetAlias","Copy Studio ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyTargetAlias","Copy Studio ID"),onClick:()=>x(i.targetAlias),children:e.jsx(M,{size:13,"aria-hidden":"true"})})})]}),e.jsx("td",{children:i.placeName??"-"}),e.jsxs("td",{children:[i.placeId??"-",i.placeId!==void 0?e.jsx(A,{text:t("connection.targets.copyPlaceId","Copy Place ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyPlaceId","Copy Place ID"),onClick:()=>x(String(i.placeId)),children:e.jsx(M,{size:13,"aria-hidden":"true"})})}):null]}),e.jsx("td",{children:i.lastRoutedAt?U(i.lastRoutedAt,t):"-"}),e.jsx("td",{children:U(i.lastSeen,t)}),e.jsxs("td",{children:[e.jsx("span",{className:o.monoMuted,title:i.clientId,children:i.clientId.slice(0,10)}),e.jsx(A,{text:t("connection.targets.copyClientId","Copy Connection ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyClientId","Copy Connection ID"),onClick:()=>x(i.clientId),children:e.jsx(M,{size:13,"aria-hidden":"true"})})})]})]},i.clientId)):e.jsx("tr",{children:e.jsx("td",{colSpan:7,className:o.emptyRow,children:t("connection.targets.none","No Studio targets connected. Open Roblox Studio and connect WEPPY Plugin.")})})})]})})]})}const le=["debug","info","warn","error"];function D({checked:n,onChange:a,testId:t,ariaLabel:c}){return e.jsxs("label",{className:o.toggleSwitch,"data-testid":t,children:[e.jsx("input",{type:"checkbox",className:o.toggleInput,checked:n,"aria-label":c,onChange:d=>a(d.target.checked)}),e.jsx("span",{className:o.toggleTrack,"aria-hidden":"true",children:e.jsx("span",{className:o.toggleThumb})})]})}function re({settings:n,updateHotSetting:a}){const{t}=T(),[c,d]=r.useState(null),p=r.useCallback(async(s,h)=>{await a(s,h),d(s),setTimeout(()=>d(j=>j===s?null:j),2e3)},[a]);return e.jsxs("div",{className:o.card,children:[e.jsxs("div",{className:o.cardHeader,children:[e.jsx(N,{label:t("settings.general.title","General Settings"),tooltip:t("settings.general.title.tooltip","Hot settings that apply immediately when changed.")}),e.jsx(B,{text:t("settings.general.liveApply.tooltip","Changes in this section are applied immediately without a separate save button."),children:e.jsx("span",{className:`${o.headerBadge} ${o.headerBadgeLive}`,children:t("settings.general.liveApply","Live Apply")})})]}),n?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.logLevel","Log Level"),tooltip:t("settings.general.logLevel.tooltip","Sets how much detail WEPPY Dashboard writes to its logs.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("select",{className:o.select,value:n.hot.LOG_LEVEL,onChange:s=>p("LOG_LEVEL",s.target.value),children:le.map(s=>e.jsx("option",{value:s,children:s},s))}),c==="LOG_LEVEL"&&e.jsx("span",{className:o.savedIndicator,children:t("settings.general.applied")})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.localHistory","Tool History Recording"),tooltip:t("settings.general.localHistory.tooltip","Stores local tool execution history for the WEPPY Dashboard history views.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_LOCAL_HISTORY"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_LOCAL_HISTORY,ariaLabel:t("settings.general.localHistory","Tool History Recording"),testId:"settings-toggle-enable-local-history",onChange:s=>p("ENABLE_LOCAL_HISTORY",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.localStatistics","Tool Statistics Collection"),tooltip:t("settings.general.localStatistics.tooltip","Aggregates local usage statistics for WEPPY Dashboard reporting.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_LOCAL_STATISTICS"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_LOCAL_STATISTICS,ariaLabel:t("settings.general.localStatistics","Tool Statistics Collection"),testId:"settings-toggle-enable-local-statistics",onChange:s=>p("ENABLE_LOCAL_STATISTICS",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.contextCapture","Context Capture"),tooltip:t("settings.general.contextCapture.tooltip","When enabled, WEPPY Dashboard records structured execution context for changelog and playtest views.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_CONTEXT_CAPTURE"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_CONTEXT_CAPTURE,ariaLabel:t("settings.general.contextCapture","Context Capture"),testId:"settings-toggle-enable-context-capture",onChange:s=>p("ENABLE_CONTEXT_CAPTURE",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.requestTimeout","Action Timeout"),tooltip:t("settings.general.requestTimeout.tooltip","Maximum time WEPPY Dashboard waits for an action before it fails.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("input",{type:"number",className:o.numberInput,value:n.hot.REQUEST_TIMEOUT,min:1e3,max:12e4,step:1e3,onChange:s=>{const h=parseInt(s.target.value,10);isNaN(h)||p("REQUEST_TIMEOUT",h)}}),e.jsx(B,{text:t("settings.general.requestTimeout.unit.tooltip","Action timeout is measured in milliseconds."),children:e.jsx("span",{className:o.unit,children:t("settings.general.requestTimeout.unit","ms")})}),c==="REQUEST_TIMEOUT"&&e.jsx("span",{className:o.savedIndicator,children:t("settings.general.applied","Applied")})]})]})]}):e.jsx("div",{className:o.loading,children:t("settings.unavailable")})]})}function je(){const{t:n}=T(),{search:a}=_(),{settings:t,updateHotSetting:c,loading:d}=te();return r.useMemo(()=>new URLSearchParams(a).get("section"),[a])==="license"?e.jsx(J,{to:"/settings?section=license",replace:!0}):d?e.jsx("div",{className:o.page,children:e.jsx("div",{className:o.loading,children:n("common.loading")})}):e.jsxs("div",{className:o.page,children:[e.jsx(ee,{title:n("page.controls.title","Controls"),description:n("page.controls.description","Manage project root, Studio routing, and MCP live settings."),helpTopicId:"controls"}),e.jsx(se,{}),e.jsx(ae,{}),e.jsx(re,{settings:t,updateHotSetting:c})]})}export{je as Component};
1
+ import{u as T,j as e,f as W,l as q,d as _,r,v as z,w as Q,x as X,a as H,s as K,y as Z,k as A,N as J}from"./index-CnXGGM07.js";import{P as ee}from"./PageHeader-Bfy2f-GH.js";import{I as N}from"./InfoLabel-BAhsgLcj.js";import{s as g}from"./ConfirmModal.module-D1aZY2bQ.js";import{T as B}from"./TooltipText-CGH7dKN6.js";import{s as o,u as te}from"./useSettings-DKMlodE_.js";import{C as M}from"./copy-D-nSZB9j.js";function k(n,a){return e.jsxs("div",{className:g.pathBlock,children:[e.jsx("span",{className:g.pathLabel,children:n}),e.jsx("code",{className:g.pathCode,children:a})]})}function oe(n){const t=/^[A-Z]:\\/i.test(n)||n.includes("\\")?"\\":"/";return`${n.replace(/[\\/]+$/,"")}${t}weppy-project-sync`}function ne({open:n,step:a,selectedProjectRoot:t,studioConnected:c,loading:d=!1,errorMessage:p=null,onClose:s,onPick:h,onApply:j}){const{t:l}=T();if(!n)return null;const S=t?oe(t):"";return e.jsx("div",{className:g.backdrop,onClick:d?void 0:s,role:"presentation",children:e.jsxs("div",{className:g.modal,onClick:y=>y.stopPropagation(),role:"dialog","aria-modal":"true","aria-labelledby":"project-root-change-modal-title",children:[e.jsx("h2",{id:"project-root-change-modal-title",className:g.title,children:a==="initial"?l("header.projectRootModal.initial.title","Change project root"):l("header.projectRootModal.confirm.title","Confirm new project root")}),e.jsx("p",{className:g.message,children:a==="initial"?c?l("header.projectRootModal.initial.body.connected","MCP will switch to the new project root and resync current Studio contents into the new target."):l("header.projectRootModal.initial.body.disconnected","MCP will switch to the new project root and use the new folder as the next sync target."):l("header.projectRootModal.confirm.body","Review the selected project folder before applying.")}),e.jsxs("div",{className:g.bodyGrid,children:[a==="initial"?e.jsxs(e.Fragment,{children:[k(l("header.projectRootModal.initial.nextSyncRoot","New sync target after selection"),l("header.projectRootModal.initial.nextSyncRoot.placeholder","<selected project folder>/weppy-project-sync")),e.jsxs("ul",{className:g.warningList,children:[c?e.jsxs(e.Fragment,{children:[e.jsx("li",{children:l("header.projectRootModal.initial.warningStop","Current sync stops immediately.")}),e.jsx("li",{children:l("header.projectRootModal.initial.warningFreshSync","The current Studio contents will be used to build a fresh full sync in the new target.")})]}):e.jsx("li",{children:l("header.projectRootModal.initial.warningDeferredSync","If Studio is not connected, full resync starts the next time the plugin connects.")}),e.jsx("li",{children:l("header.projectRootModal.initial.warningNoMove","Old sync folders are not moved automatically.")})]})]}):e.jsxs(e.Fragment,{children:[k(l("header.projectRootModal.confirm.projectRoot","Selected project folder"),t??""),k(l("header.projectRootModal.confirm.syncRoot","New sync target"),S),e.jsx("p",{className:g.message,children:l("header.projectRootModal.confirm.warningNoMove","Existing sync folders are not moved automatically.")})]}),p?e.jsx("p",{className:`${g.message} ${g.errorMessage}`,children:p}):null]}),e.jsxs("div",{className:g.actions,children:[e.jsx("button",{className:g.cancelButton,onClick:s,disabled:d,children:l("header.projectRootModal.cancel","Cancel")}),a==="initial"?e.jsx("button",{className:g.confirmButton,onClick:h,disabled:d,children:d?"...":l("header.projectRootModal.pick","Choose folder")}):e.jsx("button",{className:g.confirmButton,onClick:j,disabled:d||!t,children:d?"...":l("header.projectRootModal.apply","Apply change")})]})]})})}function F(n,a){if(n&&typeof n=="object"&&"message"in n&&typeof n.message=="string"){const t=n.message.trim();if(t.length>0)return t}return a}function se(){const{level:n,status:a}=W(),{t}=T(),{show:c}=q(),{search:d}=_(),p=r.useRef(null),[s,h]=r.useState(null),[j,l]=r.useState(!1),[S,y]=r.useState(null),[m,R]=r.useState(null),[f,v]=r.useState(!1),[w,L]=r.useState(!1),[I,x]=r.useState(null),i=r.useMemo(()=>new URLSearchParams(d).get("section")==="project-root",[d]),C=r.useCallback(async()=>{if(n==="disconnected"){h(null),l(!1);return}l(!1);try{const u=await z();h(u)}catch{h(null),l(!0)}},[n]);r.useEffect(()=>{C()},[C,a==null?void 0:a.connectedClients,a==null?void 0:a.sessionId]),r.useEffect(()=>{var u,P,O;i&&((P=(u=p.current)==null?void 0:u.scrollIntoView)==null||P.call(u,{block:"start",behavior:"smooth"}),(O=p.current)==null||O.focus())},[i]);const b=(u=!1)=>{!u&&(f||w)||(y(null),R(null),x(null))},E=()=>{n==="disconnected"||!s||(x(null),R(null),y("initial"))},Y=async()=>{v(!0),x(null);try{const u=await X();if(u.cancelled||!u.projectRoot){b(!0);return}R(u.projectRoot),y("confirm")}catch(u){x(F(u,t("header.projectRootModal.error","Failed to change project root")))}finally{v(!1)}},G=async()=>{if(m){L(!0),x(null);try{const u=await Q(m);h(u),l(!1),b(!0)}catch(u){const P=F(u,t("header.projectRootModal.error","Failed to change project root"));x(P),c(P,"error")}finally{L(!1)}}},$=j?t("controls.projectRoot.unavailable","Project root unavailable"):t("common.loading","Loading..."),V=n==="disconnected"||!s;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{id:"controls-project-root",ref:p,tabIndex:-1,className:o.card,children:[e.jsxs("div",{className:o.cardHeader,children:[e.jsx(N,{label:t("controls.projectRoot.title","Project Root"),tooltip:t("controls.projectRoot.title.tooltip","Authoritative project root and sync target used by MCP.")}),e.jsx(B,{text:t("controls.projectRoot.live.tooltip","Changing this updates MCP runtime state immediately after confirmation."),children:e.jsx("span",{className:`${o.headerBadge} ${o.headerBadgeLive}`,children:t("settings.general.liveApply","Live Apply")})})]}),e.jsxs("dl",{className:o.controlGrid,children:[e.jsx("dt",{children:t("controls.projectRoot.projectRoot","Project Root")}),e.jsx("dd",{children:(s==null?void 0:s.projectRoot)??$}),e.jsx("dt",{children:t("controls.projectRoot.syncRoot","Sync Root")}),e.jsx("dd",{children:(s==null?void 0:s.projectSyncRoot)??$})]}),e.jsx("p",{className:o.controlHint,children:t("controls.projectRoot.hint","Use this only when MCP should write sync data under a different project folder. Existing sync folders are not moved automatically.")}),e.jsx("button",{type:"button",className:o.actionBtn,disabled:V,onClick:E,children:t("header.changeProjectRoot","Change Project Root")})]}),e.jsx(ne,{open:S!==null,step:S??"initial",selectedProjectRoot:m,studioConnected:n==="studioConnected",loading:f||w,errorMessage:I,onClose:b,onPick:Y,onApply:G})]})}function ie(n){if(!n)return null;const a=n.placeName?n.placeId!==void 0?`${n.placeName} · ${n.placeId}`:n.placeName:n.placeId!==void 0?String(n.placeId):null;return a?`${n.targetAlias} · ${a}`:n.targetAlias}function U(n,a){const t=Math.max(0,Math.floor((Date.now()-n)/1e3));return t<60?`${t}${a("connection.time.secondsAgo","s ago")}`:t<3600?`${Math.floor(t/60)}${a("connection.time.minutesAgo","m ago")}`:`${Math.floor(t/3600)}${a("connection.time.hoursAgo","h ago")}`}function ae(){const{status:n,level:a}=W(),{t}=T(),{show:c}=q(),{search:d}=_(),p=r.useRef(null),[s,h]=r.useState(null),[j,l]=r.useState(null),S=r.useMemo(()=>new URLSearchParams(d).get("section")==="studio-routing",[d]),y=r.useCallback(async()=>{if(a==="disconnected"){h(null);return}try{const i=await H.get("/api/dashboard/studio-routing");h(i)}catch{h(null)}},[a]);r.useEffect(()=>{y()},[y,n==null?void 0:n.connectedClients,n==null?void 0:n.sessionId]),r.useEffect(()=>{var i,C,b;S&&((C=(i=p.current)==null?void 0:i.scrollIntoView)==null||C.call(i,{block:"start",behavior:"smooth"}),(b=p.current)==null||b.focus())},[S]);const m=(s==null?void 0:s.studioRoutingMode)??(n==null?void 0:n.studioRoutingMode)??"recentPriority",R=(s==null?void 0:s.pinnedTargetClientId)??(n==null?void 0:n.pinnedTargetClientId)??null,f=K((s==null?void 0:s.targets)??(n==null?void 0:n.pluginClients)??[],m,R),v=(s==null?void 0:s.priorityTarget)??Z(f,m,R),w=ie(v),L=new Set(f.filter(i=>i.placeId!==void 0).map(i=>i.placeId).filter((i,C,b)=>b.filter(E=>E===i).length>1)),I=async i=>{l(i.studioRoutingMode==="pinned"?i.pinnedTargetClientId??"pinned":"recentPriority");try{const C=await H.patch("/api/dashboard/studio-routing",i);h(C)}catch{c(t("connection.routing.updateFailed","Failed to update routing target"),"error")}finally{l(null)}},x=async i=>{try{await navigator.clipboard.writeText(i),c(t("connection.targets.copied","Copied value"),"success")}catch{c(t("connection.targets.copyFailed","Failed to copy value"),"error")}};return e.jsxs("div",{id:"controls-studio-routing",ref:p,tabIndex:-1,className:o.card,children:[e.jsx("div",{className:o.cardHeader,children:e.jsx(N,{label:t("controls.studioRouting.title","Studio Routing"),tooltip:t("controls.studioRouting.title.tooltip","Routing priority for MCP requests that do not name a Studio target.")})}),e.jsxs("div",{className:o.routingOverview,children:[e.jsxs("div",{className:o.routingOverviewCopy,children:[e.jsx("span",{className:o.routingEyebrow,children:t("controls.studioRouting.priorityTitle","Priority for requests without a named Studio target")}),e.jsx("strong",{children:m==="pinned"?t("connection.routing.pinned","Manual: Pinned Studio"):t("connection.routing.recentPriority","Automatic: Recent priority")}),e.jsx("p",{children:t("controls.studioRouting.priorityDescription","Explicit Studio ID, Connection ID, or Place ID requests bypass this priority setting and route to the named Studio.")})]}),e.jsxs("div",{className:o.priorityTargetSummary,children:[e.jsx("span",{children:t("controls.studioRouting.currentPriorityTarget","Current priority target")}),e.jsx("strong",{children:w??t("controls.studioRouting.noPriorityTarget","No connected Studio target")})]})]}),e.jsxs("div",{className:o.studioRoutingChoiceControl,role:"group","aria-label":t("connection.routing.priorityControl","Priority mode for requests without a named Studio target"),children:[e.jsxs("button",{type:"button",className:m==="recentPriority"?o.segmentActive:o.segment,disabled:j!==null,"aria-pressed":m==="recentPriority",onClick:()=>I({studioRoutingMode:"recentPriority"}),children:[e.jsx("span",{children:t("connection.routing.recentPriority","Automatic: Recent priority")}),e.jsx("small",{children:t("controls.studioRouting.recentPriorityHelp","Requests the highest-priority active Studio, based on recent routed commands and connection order.")})]}),e.jsxs("button",{type:"button",className:m==="pinned"?o.segmentActive:o.segment,disabled:!f.length||j!==null,"aria-pressed":m==="pinned",onClick:()=>I({studioRoutingMode:"pinned"}),children:[e.jsx("span",{children:t("connection.routing.pinned","Manual: Pinned Studio")}),e.jsx("small",{children:t("controls.studioRouting.pinnedHelp","Requests the pinned Studio unless the agent names a Studio ID, Connection ID, or Place ID.")})]})]}),L.size>0?e.jsx("p",{className:o.routingWarning,children:t("controls.studioRouting.duplicatePlaceWarning","More than one connected Studio window has the same Place ID. Ask the AI agent to use Studio ID for that place.")}):null,e.jsx("div",{className:o.tableWrap,children:e.jsxs("table",{className:o.table,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:t("connection.targets.routing","Routing")}),e.jsx("th",{children:t("connection.targets.target","Studio ID")}),e.jsx("th",{children:t("connection.targets.place","Place")}),e.jsx("th",{children:t("connection.targets.placeId","Place ID")}),e.jsx("th",{children:t("connection.targets.lastUsed","Last Used")}),e.jsx("th",{children:t("connection.targets.lastSeen","Last Seen")}),e.jsx("th",{children:t("connection.targets.clientId","Connection ID")})]})}),e.jsx("tbody",{children:f.length>0?f.map(i=>e.jsxs("tr",{children:[e.jsx("td",{children:m==="pinned"&&R===i.clientId?e.jsx("span",{className:o.routingBadge,children:t("connection.routing.pinnedBadge","Pinned")}):m==="recentPriority"&&(v==null?void 0:v.clientId)===i.clientId?e.jsx("span",{className:o.routingBadge,children:t("connection.routing.priorityBadge","Priority")}):m==="pinned"?e.jsx("button",{type:"button",className:o.setPriorityTargetButton,disabled:j!==null,onClick:()=>I({studioRoutingMode:"pinned",pinnedTargetClientId:i.clientId}),children:t("connection.routing.setPriorityTarget","Set as priority target")}):null}),e.jsxs("td",{children:[e.jsx("span",{className:o.monoMuted,title:i.clientId,children:i.targetAlias}),e.jsx(A,{text:t("connection.targets.copyTargetAlias","Copy Studio ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyTargetAlias","Copy Studio ID"),onClick:()=>x(i.targetAlias),children:e.jsx(M,{size:13,"aria-hidden":"true"})})})]}),e.jsx("td",{children:i.placeName??"-"}),e.jsxs("td",{children:[i.placeId??"-",i.placeId!==void 0?e.jsx(A,{text:t("connection.targets.copyPlaceId","Copy Place ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyPlaceId","Copy Place ID"),onClick:()=>x(String(i.placeId)),children:e.jsx(M,{size:13,"aria-hidden":"true"})})}):null]}),e.jsx("td",{children:i.lastRoutedAt?U(i.lastRoutedAt,t):"-"}),e.jsx("td",{children:U(i.lastSeen,t)}),e.jsxs("td",{children:[e.jsx("span",{className:o.monoMuted,title:i.clientId,children:i.clientId.slice(0,10)}),e.jsx(A,{text:t("connection.targets.copyClientId","Copy Connection ID"),children:e.jsx("button",{type:"button",className:o.copyIconButton,"aria-label":t("connection.targets.copyClientId","Copy Connection ID"),onClick:()=>x(i.clientId),children:e.jsx(M,{size:13,"aria-hidden":"true"})})})]})]},i.clientId)):e.jsx("tr",{children:e.jsx("td",{colSpan:7,className:o.emptyRow,children:t("connection.targets.none","No Studio targets connected. Open Roblox Studio and connect WEPPY Plugin.")})})})]})})]})}const le=["debug","info","warn","error"];function D({checked:n,onChange:a,testId:t,ariaLabel:c}){return e.jsxs("label",{className:o.toggleSwitch,"data-testid":t,children:[e.jsx("input",{type:"checkbox",className:o.toggleInput,checked:n,"aria-label":c,onChange:d=>a(d.target.checked)}),e.jsx("span",{className:o.toggleTrack,"aria-hidden":"true",children:e.jsx("span",{className:o.toggleThumb})})]})}function re({settings:n,updateHotSetting:a}){const{t}=T(),[c,d]=r.useState(null),p=r.useCallback(async(s,h)=>{await a(s,h),d(s),setTimeout(()=>d(j=>j===s?null:j),2e3)},[a]);return e.jsxs("div",{className:o.card,children:[e.jsxs("div",{className:o.cardHeader,children:[e.jsx(N,{label:t("settings.general.title","General Settings"),tooltip:t("settings.general.title.tooltip","Hot settings that apply immediately when changed.")}),e.jsx(B,{text:t("settings.general.liveApply.tooltip","Changes in this section are applied immediately without a separate save button."),children:e.jsx("span",{className:`${o.headerBadge} ${o.headerBadgeLive}`,children:t("settings.general.liveApply","Live Apply")})})]}),n?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.logLevel","Log Level"),tooltip:t("settings.general.logLevel.tooltip","Sets how much detail WEPPY Dashboard writes to its logs.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("select",{className:o.select,value:n.hot.LOG_LEVEL,onChange:s=>p("LOG_LEVEL",s.target.value),children:le.map(s=>e.jsx("option",{value:s,children:s},s))}),c==="LOG_LEVEL"&&e.jsx("span",{className:o.savedIndicator,children:t("settings.general.applied")})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.localHistory","Tool History Recording"),tooltip:t("settings.general.localHistory.tooltip","Stores local tool execution history for the WEPPY Dashboard history views.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_LOCAL_HISTORY"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_LOCAL_HISTORY,ariaLabel:t("settings.general.localHistory","Tool History Recording"),testId:"settings-toggle-enable-local-history",onChange:s=>p("ENABLE_LOCAL_HISTORY",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.localStatistics","Tool Statistics Collection"),tooltip:t("settings.general.localStatistics.tooltip","Aggregates local usage statistics for WEPPY Dashboard reporting.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_LOCAL_STATISTICS"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_LOCAL_STATISTICS,ariaLabel:t("settings.general.localStatistics","Tool Statistics Collection"),testId:"settings-toggle-enable-local-statistics",onChange:s=>p("ENABLE_LOCAL_STATISTICS",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.contextCapture","Context Capture"),tooltip:t("settings.general.contextCapture.tooltip","When enabled, WEPPY Dashboard records structured execution context for changelog and playtest views.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("span",{className:`${o.savedIndicator} ${c==="ENABLE_CONTEXT_CAPTURE"?"":o.savedIndicatorHidden}`,children:t("settings.general.applied","Applied")}),e.jsx(D,{checked:n.hot.ENABLE_CONTEXT_CAPTURE,ariaLabel:t("settings.general.contextCapture","Context Capture"),testId:"settings-toggle-enable-context-capture",onChange:s=>p("ENABLE_CONTEXT_CAPTURE",s)})]})]}),e.jsxs("div",{className:o.settingRow,children:[e.jsx("span",{className:o.settingLabel,children:e.jsx(N,{label:t("settings.general.requestTimeout","Action Timeout"),tooltip:t("settings.general.requestTimeout.tooltip","Maximum time WEPPY Dashboard waits for an action before it fails.")})}),e.jsxs("div",{className:o.settingControl,children:[e.jsx("input",{type:"number",className:o.numberInput,value:n.hot.REQUEST_TIMEOUT,min:1e3,max:12e4,step:1e3,onChange:s=>{const h=parseInt(s.target.value,10);isNaN(h)||p("REQUEST_TIMEOUT",h)}}),e.jsx(B,{text:t("settings.general.requestTimeout.unit.tooltip","Action timeout is measured in milliseconds."),children:e.jsx("span",{className:o.unit,children:t("settings.general.requestTimeout.unit","ms")})}),c==="REQUEST_TIMEOUT"&&e.jsx("span",{className:o.savedIndicator,children:t("settings.general.applied","Applied")})]})]})]}):e.jsx("div",{className:o.loading,children:t("settings.unavailable")})]})}function je(){const{t:n}=T(),{search:a}=_(),{settings:t,updateHotSetting:c,loading:d}=te();return r.useMemo(()=>new URLSearchParams(a).get("section"),[a])==="license"?e.jsx(J,{to:"/settings?section=license",replace:!0}):d?e.jsx("div",{className:o.page,children:e.jsx("div",{className:o.loading,children:n("common.loading")})}):e.jsxs("div",{className:o.page,children:[e.jsx(ee,{title:n("page.controls.title","Controls"),description:n("page.controls.description","Manage project root, Studio routing, and MCP live settings."),helpTopicId:"controls"}),e.jsx(se,{}),e.jsx(ae,{}),e.jsx(re,{settings:t,updateHotSetting:c})]})}export{je as Component};
@@ -1 +1 @@
1
- import{u as h,r as f,j as a,g as _}from"./index-BDJHcdyQ.js";import{B as x}from"./PageHeader-B0qiATU4.js";const j="_scope_1kz7c_1",m="_main_1kz7c_13",k="_label_1kz7c_20",I="_selectorLabel_1kz7c_28",w="_placeSelect_1kz7c_35",z="_name_1kz7c_48",A="_id_1kz7c_59",L="_scopeBadge_1kz7c_66",y="_copy_1kz7c_70",E="_note_1kz7c_82",n={scope:j,main:m,label:k,selectorLabel:I,placeSelect:w,name:z,id:A,scopeBadge:L,copy:y,note:E};function d(e,l){return l===null?null:e.places.find(c=>c.placeId===l)??null}function S(e){var l;return e.lastActivePlaceId!==null?e.lastActivePlaceId:((l=e.places[0])==null?void 0:l.placeId)??null}function B(e){return e.pluginConnected&&e.activePlaceId!==null?e.activePlaceId:S(e)}function U(e,l){if(e.pluginConnected&&e.activePlaceId!==null){const o=d(e,e.activePlaceId);return{label:l("placeScope.current.label","Current Place"),placeId:e.activePlaceId,placeName:e.activePlaceName??(o==null?void 0:o.placeName)??l("placeScope.unknownPlace","Unknown place"),badge:l("placeScope.live","Live"),live:!0,note:null}}const c=S(e),s=d(e,c);if(c!==null){const o=c===e.lastActivePlaceId?e.lastActivePlaceName:null;return{label:l("placeScope.lastActive.label","Last Active Place"),placeId:c,placeName:o??(s==null?void 0:s.placeName)??l("placeScope.unknownPlace","Unknown place"),badge:l("placeScope.pluginRequired","Plugin required"),live:!1,note:l("placeScope.pluginRequired.note","Connect WEPPY Plugin to confirm the live active place.")}}return{label:l("placeScope.noPlace.label","Place scope"),placeId:null,placeName:l("placeScope.noPlace.value","No place data available yet"),badge:l("placeScope.noPlace.badge","No place"),live:!1,note:l("placeScope.noPlace.note","Connect WEPPY Plugin and sync a place to create place-scoped data.")}}function q(e,l,c){const s=typeof l=="number"?d(e,l):null,o=B(e),t=(s==null?void 0:s.placeId)??o,r=d(e,t);if(t===null)return{label:c("placeScope.noPlace.label","Place scope"),placeId:null,placeName:c("placeScope.noPlace.value","No place data available yet"),badge:c("placeScope.noPlace.badge","No place"),live:!1,note:c("placeScope.noPlace.note","Connect WEPPY Plugin and sync a place to create place-scoped data.")};const u=e.pluginConnected&&e.activePlaceId===t,b=t===e.lastActivePlaceId?e.lastActivePlaceName:null;return{label:u?c("placeScope.current.label","Current Place"):c("placeScope.selected.label","Selected Place"),placeId:t,placeName:(r==null?void 0:r.placeName)??b??c("placeScope.unknownPlace","Unknown place"),badge:u?c("placeScope.live","Live"):c("placeScope.stored","Stored"),live:u,note:u?null:c("placeScope.selected.note","Showing stored data only. Studio routing is unchanged.")}}function F(e,l){switch(e){case"sync":return l("placeScope.surface.sync","Sync status and logs use this place.");case"changelog":return l("placeScope.surface.changelog","Changelog sessions use this place.");case"playtest":return l("placeScope.surface.playtest","Playtest reports use this place.");case"uiStudio":return l("placeScope.surface.uiStudio","UI captures and change history use this place.");case"tools":return l("placeScope.surface.tools","Tool history and statistics use this place.")}}function W({surface:e,selectable:l=!1,selectedPlaceId:c=null,onSelectedPlaceIdChange:s}){const{t:o}=h(),[t,r]=f.useState(null),[u,b]=f.useState(!0);if(f.useEffect(()=>{let i=!1;async function v(){try{const g=await _();i||r(g)}catch{i||r(null)}finally{i||b(!1)}}return v(),()=>{i=!0}},[]),f.useEffect(()=>{!l||!t||typeof c!="number"||d(t,c)||s==null||s(null)},[s,l,c,t]),u)return a.jsx("div",{className:n.scope,"aria-live":"polite",children:a.jsx("span",{className:n.label,children:o("placeScope.loading","Loading place scope...")})});if(!t)return a.jsx("div",{className:n.scope,"aria-live":"polite",children:a.jsx("span",{className:n.label,children:o("placeScope.unavailable","Place scope unavailable")})});const p=l?q(t,c,o):U(t,o),N=typeof p.placeId=="number"?String(p.placeId):"",P=l&&t.places.length>0;return a.jsxs("div",{className:n.scope,"aria-live":"polite",children:[a.jsxs("div",{className:n.main,children:[P?a.jsxs(a.Fragment,{children:[a.jsxs("label",{className:n.selectorLabel,children:[a.jsx("span",{className:n.label,children:o("placeScope.selector.label","Place data")}),a.jsx("select",{className:n.placeSelect,value:N,onChange:i=>{const v=Number.parseInt(i.currentTarget.value,10);s==null||s(Number.isInteger(v)?v:null)},children:t.places.map(i=>a.jsxs("option",{value:i.placeId,children:[i.placeName," (",i.placeId,")"]},i.placeId))})]}),a.jsx("span",{className:n.label,children:p.label}),a.jsx("span",{className:n.name,children:p.placeName})]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{className:n.label,children:p.label}),a.jsx("span",{className:n.name,children:p.placeName})]}),p.placeId!==null?a.jsx("span",{className:n.id,children:p.placeId}):null,a.jsx(x,{variant:p.live?"success":"warning",shape:"pill",className:n.scopeBadge,children:p.badge})]}),a.jsxs("div",{className:n.copy,children:[a.jsx("span",{children:F(e,o)}),p.note?a.jsx("span",{className:n.note,children:p.note}):null]})]})}export{W as C};
1
+ import{u as h,r as f,j as a,g as _}from"./index-CnXGGM07.js";import{B as x}from"./PageHeader-Bfy2f-GH.js";const j="_scope_1kz7c_1",m="_main_1kz7c_13",k="_label_1kz7c_20",I="_selectorLabel_1kz7c_28",w="_placeSelect_1kz7c_35",z="_name_1kz7c_48",A="_id_1kz7c_59",L="_scopeBadge_1kz7c_66",y="_copy_1kz7c_70",E="_note_1kz7c_82",n={scope:j,main:m,label:k,selectorLabel:I,placeSelect:w,name:z,id:A,scopeBadge:L,copy:y,note:E};function d(e,l){return l===null?null:e.places.find(c=>c.placeId===l)??null}function S(e){var l;return e.lastActivePlaceId!==null?e.lastActivePlaceId:((l=e.places[0])==null?void 0:l.placeId)??null}function B(e){return e.pluginConnected&&e.activePlaceId!==null?e.activePlaceId:S(e)}function U(e,l){if(e.pluginConnected&&e.activePlaceId!==null){const o=d(e,e.activePlaceId);return{label:l("placeScope.current.label","Current Place"),placeId:e.activePlaceId,placeName:e.activePlaceName??(o==null?void 0:o.placeName)??l("placeScope.unknownPlace","Unknown place"),badge:l("placeScope.live","Live"),live:!0,note:null}}const c=S(e),s=d(e,c);if(c!==null){const o=c===e.lastActivePlaceId?e.lastActivePlaceName:null;return{label:l("placeScope.lastActive.label","Last Active Place"),placeId:c,placeName:o??(s==null?void 0:s.placeName)??l("placeScope.unknownPlace","Unknown place"),badge:l("placeScope.pluginRequired","Plugin required"),live:!1,note:l("placeScope.pluginRequired.note","Connect WEPPY Plugin to confirm the live active place.")}}return{label:l("placeScope.noPlace.label","Place scope"),placeId:null,placeName:l("placeScope.noPlace.value","No place data available yet"),badge:l("placeScope.noPlace.badge","No place"),live:!1,note:l("placeScope.noPlace.note","Connect WEPPY Plugin and sync a place to create place-scoped data.")}}function q(e,l,c){const s=typeof l=="number"?d(e,l):null,o=B(e),t=(s==null?void 0:s.placeId)??o,r=d(e,t);if(t===null)return{label:c("placeScope.noPlace.label","Place scope"),placeId:null,placeName:c("placeScope.noPlace.value","No place data available yet"),badge:c("placeScope.noPlace.badge","No place"),live:!1,note:c("placeScope.noPlace.note","Connect WEPPY Plugin and sync a place to create place-scoped data.")};const u=e.pluginConnected&&e.activePlaceId===t,b=t===e.lastActivePlaceId?e.lastActivePlaceName:null;return{label:u?c("placeScope.current.label","Current Place"):c("placeScope.selected.label","Selected Place"),placeId:t,placeName:(r==null?void 0:r.placeName)??b??c("placeScope.unknownPlace","Unknown place"),badge:u?c("placeScope.live","Live"):c("placeScope.stored","Stored"),live:u,note:u?null:c("placeScope.selected.note","Showing stored data only. Studio routing is unchanged.")}}function F(e,l){switch(e){case"sync":return l("placeScope.surface.sync","Sync status and logs use this place.");case"changelog":return l("placeScope.surface.changelog","Changelog sessions use this place.");case"playtest":return l("placeScope.surface.playtest","Playtest reports use this place.");case"uiStudio":return l("placeScope.surface.uiStudio","UI captures and change history use this place.");case"tools":return l("placeScope.surface.tools","Tool history and statistics use this place.")}}function W({surface:e,selectable:l=!1,selectedPlaceId:c=null,onSelectedPlaceIdChange:s}){const{t:o}=h(),[t,r]=f.useState(null),[u,b]=f.useState(!0);if(f.useEffect(()=>{let i=!1;async function v(){try{const g=await _();i||r(g)}catch{i||r(null)}finally{i||b(!1)}}return v(),()=>{i=!0}},[]),f.useEffect(()=>{!l||!t||typeof c!="number"||d(t,c)||s==null||s(null)},[s,l,c,t]),u)return a.jsx("div",{className:n.scope,"aria-live":"polite",children:a.jsx("span",{className:n.label,children:o("placeScope.loading","Loading place scope...")})});if(!t)return a.jsx("div",{className:n.scope,"aria-live":"polite",children:a.jsx("span",{className:n.label,children:o("placeScope.unavailable","Place scope unavailable")})});const p=l?q(t,c,o):U(t,o),N=typeof p.placeId=="number"?String(p.placeId):"",P=l&&t.places.length>0;return a.jsxs("div",{className:n.scope,"aria-live":"polite",children:[a.jsxs("div",{className:n.main,children:[P?a.jsxs(a.Fragment,{children:[a.jsxs("label",{className:n.selectorLabel,children:[a.jsx("span",{className:n.label,children:o("placeScope.selector.label","Place data")}),a.jsx("select",{className:n.placeSelect,value:N,onChange:i=>{const v=Number.parseInt(i.currentTarget.value,10);s==null||s(Number.isInteger(v)?v:null)},children:t.places.map(i=>a.jsxs("option",{value:i.placeId,children:[i.placeName," (",i.placeId,")"]},i.placeId))})]}),a.jsx("span",{className:n.label,children:p.label}),a.jsx("span",{className:n.name,children:p.placeName})]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{className:n.label,children:p.label}),a.jsx("span",{className:n.name,children:p.placeName})]}),p.placeId!==null?a.jsx("span",{className:n.id,children:p.placeId}):null,a.jsx(x,{variant:p.live?"success":"warning",shape:"pill",className:n.scopeBadge,children:p.badge})]}),a.jsxs("div",{className:n.copy,children:[a.jsx("span",{children:F(e,o)}),p.note?a.jsx("span",{className:n.note,children:p.note}):null]})]})}export{W as C};
@@ -1,4 +1,4 @@
1
- import{u as _,r as x,j as e}from"./index-BDJHcdyQ.js";const N="_container_uv8oc_2",j="_header_uv8oc_10",v="_modeBtn_uv8oc_18",g="_modeBtnActive_uv8oc_33",w="_unifiedView_uv8oc_40",L="_diffLine_uv8oc_46",b="_lineNum_uv8oc_55",C="_lineContent_uv8oc_64",S="_lineAdded_uv8oc_68",V="_lineRemoved_uv8oc_73",B="_lineContext_uv8oc_78",$="_sideBySide_uv8oc_83",A="_sidePane_uv8oc_90",P="_sideLabel_uv8oc_100",R="_sideContent_uv8oc_112",D="_empty_uv8oc_117",s={container:N,header:j,modeBtn:v,modeBtnActive:g,unifiedView:w,diffLine:L,lineNum:b,lineContent:C,lineAdded:S,lineRemoved:V,lineContext:B,sideBySide:$,sidePane:A,sideLabel:P,sideContent:R,empty:D};function k(n,i){const l=n.split(`
1
+ import{u as _,r as x,j as e}from"./index-CnXGGM07.js";const N="_container_uv8oc_2",j="_header_uv8oc_10",v="_modeBtn_uv8oc_18",g="_modeBtnActive_uv8oc_33",w="_unifiedView_uv8oc_40",L="_diffLine_uv8oc_46",b="_lineNum_uv8oc_55",C="_lineContent_uv8oc_64",S="_lineAdded_uv8oc_68",V="_lineRemoved_uv8oc_73",B="_lineContext_uv8oc_78",$="_sideBySide_uv8oc_83",A="_sidePane_uv8oc_90",P="_sideLabel_uv8oc_100",R="_sideContent_uv8oc_112",D="_empty_uv8oc_117",s={container:N,header:j,modeBtn:v,modeBtnActive:g,unifiedView:w,diffLine:L,lineNum:b,lineContent:C,lineAdded:S,lineRemoved:V,lineContext:B,sideBySide:$,sidePane:A,sideLabel:P,sideContent:R,empty:D};function k(n,i){const l=n.split(`
2
2
  `),d=i.split(`
3
3
  `),a=[],f=Math.max(l.length,d.length);let t=0,r=0;for(;(t<l.length||r<d.length)&&(t<l.length&&r<d.length?l[t]===d[r]?(a.push({type:"context",content:l[t],lineNum:r+1}),t++,r++):(a.push({type:"removed",content:l[t],lineNum:t+1}),t++,t<l.length&&l[t]===d[r]?(a.push({type:"added",content:d[r],lineNum:r+1}),r++):r<d.length&&(a.push({type:"added",content:d[r],lineNum:r+1}),r++)):t<l.length?(a.push({type:"removed",content:l[t],lineNum:t+1}),t++):r<d.length&&(a.push({type:"added",content:d[r],lineNum:r+1}),r++),!(a.length>f*3)););return a}function O({before:n,after:i}){const{t:l}=_(),[d,a]=x.useState("unified"),f=typeof n=="string"?n:n!=null?JSON.stringify(n,null,2):"",t=typeof i=="string"?i:i!=null?JSON.stringify(i,null,2):"",r=x.useMemo(()=>k(f,t),[f,t]);if(!f&&!t)return e.jsx("div",{className:s.container,children:e.jsx("div",{className:s.empty,children:l("changelog.diff.empty","No diff available")})});if(!f&&t){const c=t.split(`
4
4
  `);return e.jsx("div",{className:s.container,children:e.jsx("div",{className:s.unifiedView,children:c.map((u,m)=>e.jsxs("div",{className:`${s.diffLine} ${s.lineAdded}`,children:[e.jsx("span",{className:s.lineNum,children:m+1}),e.jsxs("span",{className:s.lineContent,children:["+ ",u]})]},m))})})}return e.jsxs("div",{className:s.container,children:[e.jsxs("div",{className:s.header,children:[e.jsx("button",{className:`${s.modeBtn} ${d==="unified"?s.modeBtnActive:""}`,onClick:()=>a("unified"),children:l("changelog.diff.unified","Unified")}),e.jsx("button",{className:`${s.modeBtn} ${d==="side-by-side"?s.modeBtnActive:""}`,onClick:()=>a("side-by-side"),children:l("changelog.diff.sideBySide","Side by Side")})]}),d==="unified"?e.jsx("div",{className:s.unifiedView,children:r.map((c,u)=>e.jsxs("div",{className:`${s.diffLine} ${c.type==="added"?s.lineAdded:c.type==="removed"?s.lineRemoved:s.lineContext}`,children:[e.jsx("span",{className:s.lineNum,children:c.lineNum??""}),e.jsxs("span",{className:s.lineContent,children:[c.type==="added"?"+ ":c.type==="removed"?"- ":" ",c.content]})]},u))}):e.jsxs("div",{className:s.sideBySide,children:[e.jsxs("div",{className:s.sidePane,children:[e.jsx("div",{className:s.sideLabel,children:l("changelog.diff.before","Before")}),e.jsx("div",{className:s.sideContent,children:f.split(`
@@ -1 +1 @@
1
- import{j as r,k as e}from"./index-BDJHcdyQ.js";function s({label:t,tooltip:o}){return r.jsx(e,{text:o,children:t})}export{s as I};
1
+ import{j as r,k as e}from"./index-CnXGGM07.js";function s({label:t,tooltip:o}){return r.jsx(e,{text:o,children:t})}export{s as I};
@@ -1 +1 @@
1
- import{j as t,u as R,r as v,f as L,h as F,a as M,D as V}from"./index-BDJHcdyQ.js";import{I as A}from"./InfoLabel-BUXacsTE.js";import{P as U}from"./PageHeader-B0qiATU4.js";import{S as z}from"./StatusBadge-B2VLfqa6.js";import{T as O}from"./TooltipText-DaLR7eg1.js";import{G as X}from"./GameChangeDetail-D2QTkbEB.js";import{u as q,f as J}from"./useLiveUptime-KCA8LzCI.js";const K="_page_1xgxh_2",Q="_card_1xgxh_10",W="_cardHeader_1xgxh_17",Y="_disconnectCard_1xgxh_28",Z="_disconnectIcon_1xgxh_36",ee="_disconnectTitle_1xgxh_41",te="_disconnectMessage_1xgxh_48",se="_reconnectGuide_1xgxh_55",ne="_guideStep_1xgxh_64",ie="_stepNumber_1xgxh_72",ce="_reconnectIndicator_1xgxh_88",re="_reconnectDot_1xgxh_98",ae="_pulse_1xgxh_1",oe="_disconnectActions_1xgxh_112",le="_btn_1xgxh_118",de="_btnSecondary_1xgxh_134",me="_metricRow_1xgxh_152",ge="_metricGrid_1xgxh_158",he="_metricCard_1xgxh_164",xe="_metric_ok_1xgxh_174",ue="_metric_warn_1xgxh_179",ve="_metric_error_1xgxh_184",_e="_metricHeader_1xgxh_189",pe="_metricIcon_1xgxh_200",fe="_metricTitle_1xgxh_204",Ce="_metricValue_1xgxh_208",je="_metricSubtitle_1xgxh_215",we="_guideCard_1xgxh_225",Ne="_guideTitle_1xgxh_232",ye="_checklist_1xgxh_239",Te="_feedEmpty_1xgxh_263",Se="_feedList_1xgxh_270",Ie="_feedItem_1xgxh_278",be="_feedTime_1xgxh_291",ke="_feedIcon_1xgxh_298",Me="_feedSummary_1xgxh_304",De="_feedText_1xgxh_313",Be="_feedContext_1xgxh_321",He="_feedItemClickable_1xgxh_330",Ee="_feedChevron_1xgxh_338",Pe="_feedDetail_1xgxh_347",$e="_feedDetailPre_1xgxh_356",Re="_feedDetailText_1xgxh_365",Ge="_changelogSummary_1xgxh_372",Le="_changeTag_1xgxh_381",Fe="_tierBar_1xgxh_393",Ve="_tierBarTrack_1xgxh_399",Ae="_tierBarFillBasic_1xgxh_407",Ue="_tierBarFillPro_1xgxh_412",ze="_tierLabels_1xgxh_417",s={page:K,card:Q,cardHeader:W,disconnectCard:Y,disconnectIcon:Z,disconnectTitle:ee,disconnectMessage:te,reconnectGuide:se,guideStep:ne,stepNumber:ie,reconnectIndicator:ce,reconnectDot:re,pulse:ae,disconnectActions:oe,btn:le,btnSecondary:de,metricRow:me,metricGrid:ge,metricCard:he,metric_ok:xe,metric_warn:ue,metric_error:ve,metricHeader:_e,metricIcon:pe,metricTitle:fe,metricValue:Ce,metricSubtitle:je,guideCard:we,guideTitle:Ne,checklist:ye,feedEmpty:Te,feedList:Se,feedItem:Ie,feedTime:be,feedIcon:ke,feedSummary:Me,feedText:De,feedContext:Be,feedItemClickable:He,feedChevron:Ee,feedDetail:Pe,feedDetailPre:$e,feedDetailText:Re,changelogSummary:Ge,changeTag:Le,tierBar:Fe,tierBarTrack:Ve,tierBarFillBasic:Ae,tierBarFillPro:Ue,tierLabels:ze};function N({title:e,value:i,icon:c,subtitle:r,status:a,children:n}){const l=a?s[`metric_${a}`]:"";return t.jsxs("div",{className:`${s.metricCard} ${l}`,children:[t.jsxs("div",{className:s.metricHeader,children:[c&&t.jsx("span",{className:s.metricIcon,children:c}),t.jsx("span",{className:s.metricTitle,children:e})]}),t.jsx("div",{className:s.metricValue,children:i}),r&&t.jsx("div",{className:s.metricSubtitle,children:r}),n]})}function Oe(e){var c,r;const i=e==null?void 0:e.contextSummary;return(i==null?void 0:i.intent)??((r=(c=i==null?void 0:i.affectedAreas)==null?void 0:c[0])==null?void 0:r.label)??(i==null?void 0:i.testScenario)??null}function H({changes:e}){const{t:i}=R(),[c,r]=v.useState(null);return e.length===0?t.jsx("div",{className:s.feedEmpty,children:i("overview.feed.empty")}):t.jsx("div",{className:s.feedList,children:e.map((a,n)=>{const l=c===n,m=a.raw,g=m&&(m.before!=null||m.after!=null||m.details!=null),_=Oe(m);return t.jsxs("div",{children:[t.jsxs("div",{className:`${s.feedItem} ${g?s.feedItemClickable:""}`,onClick:()=>g&&r(l?null:n),children:[t.jsx("span",{className:s.feedTime,children:a.timestamp}),t.jsx("span",{className:s.feedIcon,children:a.icon}),t.jsxs("span",{className:s.feedText,children:[t.jsx("span",{className:s.feedSummary,children:a.summary}),_&&t.jsx("span",{className:s.feedContext,children:_})]}),g&&t.jsx("span",{className:s.feedChevron,children:l?"▴":"▾"})]}),l&&m&&t.jsx("div",{className:s.feedDetail,children:t.jsx(X,{change:m})})]},n)})})}const E=20;function G(e){return`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}function P(){return G(new Date)}function $(e){switch(e){case"script":return"📝";case"instance":return"🧱";case"property":return"🎨";case"lighting":return"💡";case"terrain":return"⛰️";case"asset":return"📦";default:return"🔧"}}function Xe(){const{level:e,status:i}=L(),c=F(),[r,a]=v.useState(null),[n,l]=v.useState(null),[m,g]=v.useState(null),[_,h]=v.useState([]),y=v.useRef(null),T=v.useCallback(async()=>{try{const o=await M.get("/connection-info");a(o)}catch{a(null)}},[]),S=v.useCallback(async()=>{try{const o=await M.get("/api/dashboard/changelog/active");if(g(o),o.recentChanges&&o.recentChanges.length>0){const p=o.recentChanges.map(x=>({timestamp:x.timestamp?G(new Date(x.timestamp)):P(),icon:$(x.category),summary:x.summary,category:x.category,raw:x}));h(p)}}catch{g(null)}},[]),f=v.useCallback(async()=>{try{const o=await M.get("/sync/status");l(o)}catch{l(null)}},[]);return v.useEffect(()=>{e!=="disconnected"?(T(),S(),f()):(a(null),l(null),g(null));const o=new V;y.current=o,o.connect();const p=o.on("game_change",C=>{const u=C,j={timestamp:P(),icon:$(u.category),summary:u.summary,category:u.category};h(k=>{const w=[j,...k];return w.length>E?w.slice(0,E):w}),S()}),x=o.on("sync",C=>{const u=C;l(j=>({...j,state:u.status,...u.placeId?{placeId:u.placeId}:{}}))});return()=>{p(),x(),o.disconnect(),y.current=null}},[e,T,S,f]),{level:e,status:i,connectionInfo:r,syncStatus:n,changeSummary:m,recentChanges:_,tier:c}}function D(e){return e.scriptsModified+e.scriptsCreated+e.instancesCreated+e.instancesDeleted+e.instancesMoved+e.propertiesChanged+e.assetsInserted+(e.lightingChanged?1:0)+(e.terrainChanged?1:0)}function qe(e,i){switch(e){case"syncing":return i("status.syncing","Syncing");case"initializing":return i("status.initializing","Initializing");case"error":return i("status.error","Error");default:return i("status.idle","Idle")}}function Je(e){switch(e){case"syncing":return"ok";case"initializing":return"warn";case"error":return"error";default:return"ok"}}function b(e,i,c,r){return t.jsxs("div",{className:e.metricSubtitle,children:[t.jsx(A,{label:i,tooltip:c}),": ",r]},i)}function d(e,i){return t.jsx(O,{text:i,children:e})}function st(){var w,B;const{t:e}=R(),{level:i,status:c,connectionInfo:r,syncStatus:a,changeSummary:n,recentChanges:l}=Xe(),m=q(c==null?void 0:c.uptime),g=t.jsx(U,{title:e("page.overview.title","Overview"),description:e("page.overview.description","Check server, plugin, agent, sync, and recent game-change status in one place."),helpTopicId:"overview",helpState:{connectionLevel:i}});if(i==="disconnected")return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.disconnectCard,children:[t.jsx("div",{className:s.disconnectIcon,children:"⚠️"}),t.jsx("h2",{className:s.disconnectTitle,children:e("overview.l0.title")}),t.jsx("p",{className:s.disconnectMessage,children:e("overview.l0.message")}),t.jsxs("div",{className:s.reconnectGuide,children:[t.jsxs("div",{className:s.guideStep,children:[t.jsx("span",{className:s.stepNumber,children:"1"}),t.jsx("span",{children:e("overview.l0.step1")})]}),t.jsxs("div",{className:s.guideStep,children:[t.jsx("span",{className:s.stepNumber,children:"2"}),t.jsx("span",{children:e("overview.l0.step2")})]})]}),t.jsxs("div",{className:s.reconnectIndicator,children:[t.jsx("span",{className:s.reconnectDot}),e("overview.l0.reconnecting")]}),t.jsxs("div",{className:s.disconnectActions,children:[t.jsx("button",{className:s.btn,onClick:()=>window.location.reload(),children:e("overview.l0.reconnectBtn")}),t.jsx("button",{className:s.btnSecondary,onClick:()=>{window.location.hash="#/settings"},children:e("overview.l0.settingsBtn")})]})]})]});const _=(r==null?void 0:r.mcpInstanceCount)??0,h=((w=r==null?void 0:r.mcpInstances)==null?void 0:w.find(I=>!I.isServer&&I.aiClientName))??((B=r==null?void 0:r.mcpInstances)==null?void 0:B.find(I=>!!I.aiClientName))??null,y=(c==null?void 0:c.pluginClients)??[],T=y.length>0,S=(c==null?void 0:c.sessionId)??(r==null?void 0:r.sessionId)??"-",f=e("overview.metric.server.tooltip","MCP server runtime and process status"),o=e("overview.metric.plugin.tooltip","Roblox Studio plugin connection and version status"),p=e("overview.metric.agent.tooltip","Connected AI coding agents and their runtime state"),x=e("overview.metric.sync.tooltip","Current Studio to local sync activity"),C=c?[b(s,e("overview.meta.version","Version"),e("overview.meta.version.tooltip","Installed MCP server version"),`v${c.version}`),b(s,e("overview.meta.session","Session"),e("overview.meta.session.tooltip","Current MCP session identifier"),S),b(s,e("overview.meta.pid","PID"),e("overview.meta.pid.tooltip","Operating system process identifier"),String(c.pid??"-")),b(s,e("overview.meta.uptime","Uptime"),e("overview.meta.uptime.tooltip","Time elapsed since the MCP server started"),J(m??c.uptime))]:[];if(i==="serverOnly")return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.metricRow,children:[t.jsx(N,{title:d(e("overview.metric.server"),f),value:d(e("status.online"),f),icon:"🖥️",status:"ok",children:t.jsxs(t.Fragment,{children:[C,t.jsx(z,{status:"online"})]})}),t.jsx(N,{title:d(e("overview.metric.agent"),p),value:d((h==null?void 0:h.aiClientName)??e("overview.metric.noAgent"),p),icon:"🤖",subtitle:_>1?`${_} ${e("overview.metric.agent.instancesUnit","instances")}`:void 0,status:h?"ok":"warn"})]}),t.jsxs("div",{className:s.guideCard,children:[t.jsx("h3",{className:s.guideTitle,children:e("overview.l1.pluginGuide")}),t.jsxs("ul",{className:s.checklist,children:[t.jsx("li",{children:e("overview.l1.check1")}),t.jsx("li",{children:e("overview.l1.check2")})]})]}),t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.feed.title")}),l.length>0?t.jsx(H,{changes:l}):t.jsx("div",{className:s.feedEmpty,children:e("overview.l1.feedHint")})]}),n&&D(n)>0&&t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.changelog.title")}),t.jsxs("div",{className:s.changelogSummary,children:[t.jsxs("span",{children:[e("overview.changelog.entries","Entries"),": ",D(n)]}),n.scriptsModified>0&&t.jsxs("span",{className:s.changeTag,children:["📝"," ",n.scriptsModified," ",e("overview.changelog.scripts")]}),n.instancesCreated>0&&t.jsxs("span",{className:s.changeTag,children:["🧱"," ",n.instancesCreated," ",e("overview.changelog.instances")]}),n.propertiesChanged>0&&t.jsxs("span",{className:s.changeTag,children:["🎨"," ",n.propertiesChanged," ",e("overview.changelog.properties")]}),n.assetsInserted>0&&t.jsxs("span",{className:s.changeTag,children:["📦"," ",n.assetsInserted," ",e("overview.changelog.assets")]})]})]})]});const u=y[0],j=n?D(n):0,k=!!n&&j>0;return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.metricGrid,children:[t.jsx(N,{title:d(e("overview.metric.server"),f),value:d(e("status.online"),f),icon:"🖥️",status:"ok",children:t.jsx(t.Fragment,{children:C})}),t.jsx(N,{title:d(e("overview.metric.plugin"),o),value:d(e(T?"status.online":"status.offline"),o),icon:"🔌",subtitle:u?`${u.placeName??"-"} / v${u.pluginVersion??"-"}`:void 0,status:T?"ok":"error"}),t.jsx(N,{title:d(e("overview.metric.agent"),p),value:d((h==null?void 0:h.aiClientName)??e("overview.metric.noAgent"),p),icon:"🤖",subtitle:_>1?`${_} ${e("overview.metric.agent.instancesUnit","instances")}`:void 0,status:h?"ok":"warn"}),t.jsx(N,{title:d(e("overview.metric.sync"),x),value:d(qe(a==null?void 0:a.state,e),x),icon:"🔄",status:Je(a==null?void 0:a.state)})]}),t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.feed.title")}),t.jsx(H,{changes:l})]}),k&&t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.changelog.title")}),t.jsxs("div",{className:s.changelogSummary,children:[t.jsxs("span",{children:[e("overview.changelog.entries","Entries"),": ",j]}),n.scriptsModified>0&&t.jsxs("span",{className:s.changeTag,children:["📝"," ",n.scriptsModified," ",e("overview.changelog.scripts")]}),n.instancesCreated>0&&t.jsxs("span",{className:s.changeTag,children:["🧱"," ",n.instancesCreated," ",e("overview.changelog.instances")]}),n.propertiesChanged>0&&t.jsxs("span",{className:s.changeTag,children:["🎨"," ",n.propertiesChanged," ",e("overview.changelog.properties")]}),n.assetsInserted>0&&t.jsxs("span",{className:s.changeTag,children:["📦"," ",n.assetsInserted," ",e("overview.changelog.assets")]})]})]})]})}export{st as Component};
1
+ import{j as t,u as R,r as v,f as L,h as F,a as M,D as V}from"./index-CnXGGM07.js";import{I as A}from"./InfoLabel-BAhsgLcj.js";import{P as U}from"./PageHeader-Bfy2f-GH.js";import{S as z}from"./StatusBadge-Df9BQsJU.js";import{T as O}from"./TooltipText-CGH7dKN6.js";import{G as X}from"./GameChangeDetail-CMSmIwO-.js";import{u as q,f as J}from"./useLiveUptime-1Et9Q6mq.js";const K="_page_1xgxh_2",Q="_card_1xgxh_10",W="_cardHeader_1xgxh_17",Y="_disconnectCard_1xgxh_28",Z="_disconnectIcon_1xgxh_36",ee="_disconnectTitle_1xgxh_41",te="_disconnectMessage_1xgxh_48",se="_reconnectGuide_1xgxh_55",ne="_guideStep_1xgxh_64",ie="_stepNumber_1xgxh_72",ce="_reconnectIndicator_1xgxh_88",re="_reconnectDot_1xgxh_98",ae="_pulse_1xgxh_1",oe="_disconnectActions_1xgxh_112",le="_btn_1xgxh_118",de="_btnSecondary_1xgxh_134",me="_metricRow_1xgxh_152",ge="_metricGrid_1xgxh_158",he="_metricCard_1xgxh_164",xe="_metric_ok_1xgxh_174",ue="_metric_warn_1xgxh_179",ve="_metric_error_1xgxh_184",_e="_metricHeader_1xgxh_189",pe="_metricIcon_1xgxh_200",fe="_metricTitle_1xgxh_204",Ce="_metricValue_1xgxh_208",je="_metricSubtitle_1xgxh_215",we="_guideCard_1xgxh_225",Ne="_guideTitle_1xgxh_232",ye="_checklist_1xgxh_239",Te="_feedEmpty_1xgxh_263",Se="_feedList_1xgxh_270",Ie="_feedItem_1xgxh_278",be="_feedTime_1xgxh_291",ke="_feedIcon_1xgxh_298",Me="_feedSummary_1xgxh_304",De="_feedText_1xgxh_313",Be="_feedContext_1xgxh_321",He="_feedItemClickable_1xgxh_330",Ee="_feedChevron_1xgxh_338",Pe="_feedDetail_1xgxh_347",$e="_feedDetailPre_1xgxh_356",Re="_feedDetailText_1xgxh_365",Ge="_changelogSummary_1xgxh_372",Le="_changeTag_1xgxh_381",Fe="_tierBar_1xgxh_393",Ve="_tierBarTrack_1xgxh_399",Ae="_tierBarFillBasic_1xgxh_407",Ue="_tierBarFillPro_1xgxh_412",ze="_tierLabels_1xgxh_417",s={page:K,card:Q,cardHeader:W,disconnectCard:Y,disconnectIcon:Z,disconnectTitle:ee,disconnectMessage:te,reconnectGuide:se,guideStep:ne,stepNumber:ie,reconnectIndicator:ce,reconnectDot:re,pulse:ae,disconnectActions:oe,btn:le,btnSecondary:de,metricRow:me,metricGrid:ge,metricCard:he,metric_ok:xe,metric_warn:ue,metric_error:ve,metricHeader:_e,metricIcon:pe,metricTitle:fe,metricValue:Ce,metricSubtitle:je,guideCard:we,guideTitle:Ne,checklist:ye,feedEmpty:Te,feedList:Se,feedItem:Ie,feedTime:be,feedIcon:ke,feedSummary:Me,feedText:De,feedContext:Be,feedItemClickable:He,feedChevron:Ee,feedDetail:Pe,feedDetailPre:$e,feedDetailText:Re,changelogSummary:Ge,changeTag:Le,tierBar:Fe,tierBarTrack:Ve,tierBarFillBasic:Ae,tierBarFillPro:Ue,tierLabels:ze};function N({title:e,value:i,icon:c,subtitle:r,status:a,children:n}){const l=a?s[`metric_${a}`]:"";return t.jsxs("div",{className:`${s.metricCard} ${l}`,children:[t.jsxs("div",{className:s.metricHeader,children:[c&&t.jsx("span",{className:s.metricIcon,children:c}),t.jsx("span",{className:s.metricTitle,children:e})]}),t.jsx("div",{className:s.metricValue,children:i}),r&&t.jsx("div",{className:s.metricSubtitle,children:r}),n]})}function Oe(e){var c,r;const i=e==null?void 0:e.contextSummary;return(i==null?void 0:i.intent)??((r=(c=i==null?void 0:i.affectedAreas)==null?void 0:c[0])==null?void 0:r.label)??(i==null?void 0:i.testScenario)??null}function H({changes:e}){const{t:i}=R(),[c,r]=v.useState(null);return e.length===0?t.jsx("div",{className:s.feedEmpty,children:i("overview.feed.empty")}):t.jsx("div",{className:s.feedList,children:e.map((a,n)=>{const l=c===n,m=a.raw,g=m&&(m.before!=null||m.after!=null||m.details!=null),_=Oe(m);return t.jsxs("div",{children:[t.jsxs("div",{className:`${s.feedItem} ${g?s.feedItemClickable:""}`,onClick:()=>g&&r(l?null:n),children:[t.jsx("span",{className:s.feedTime,children:a.timestamp}),t.jsx("span",{className:s.feedIcon,children:a.icon}),t.jsxs("span",{className:s.feedText,children:[t.jsx("span",{className:s.feedSummary,children:a.summary}),_&&t.jsx("span",{className:s.feedContext,children:_})]}),g&&t.jsx("span",{className:s.feedChevron,children:l?"▴":"▾"})]}),l&&m&&t.jsx("div",{className:s.feedDetail,children:t.jsx(X,{change:m})})]},n)})})}const E=20;function G(e){return`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}function P(){return G(new Date)}function $(e){switch(e){case"script":return"📝";case"instance":return"🧱";case"property":return"🎨";case"lighting":return"💡";case"terrain":return"⛰️";case"asset":return"📦";default:return"🔧"}}function Xe(){const{level:e,status:i}=L(),c=F(),[r,a]=v.useState(null),[n,l]=v.useState(null),[m,g]=v.useState(null),[_,h]=v.useState([]),y=v.useRef(null),T=v.useCallback(async()=>{try{const o=await M.get("/connection-info");a(o)}catch{a(null)}},[]),S=v.useCallback(async()=>{try{const o=await M.get("/api/dashboard/changelog/active");if(g(o),o.recentChanges&&o.recentChanges.length>0){const p=o.recentChanges.map(x=>({timestamp:x.timestamp?G(new Date(x.timestamp)):P(),icon:$(x.category),summary:x.summary,category:x.category,raw:x}));h(p)}}catch{g(null)}},[]),f=v.useCallback(async()=>{try{const o=await M.get("/sync/status");l(o)}catch{l(null)}},[]);return v.useEffect(()=>{e!=="disconnected"?(T(),S(),f()):(a(null),l(null),g(null));const o=new V;y.current=o,o.connect();const p=o.on("game_change",C=>{const u=C,j={timestamp:P(),icon:$(u.category),summary:u.summary,category:u.category};h(k=>{const w=[j,...k];return w.length>E?w.slice(0,E):w}),S()}),x=o.on("sync",C=>{const u=C;l(j=>({...j,state:u.status,...u.placeId?{placeId:u.placeId}:{}}))});return()=>{p(),x(),o.disconnect(),y.current=null}},[e,T,S,f]),{level:e,status:i,connectionInfo:r,syncStatus:n,changeSummary:m,recentChanges:_,tier:c}}function D(e){return e.scriptsModified+e.scriptsCreated+e.instancesCreated+e.instancesDeleted+e.instancesMoved+e.propertiesChanged+e.assetsInserted+(e.lightingChanged?1:0)+(e.terrainChanged?1:0)}function qe(e,i){switch(e){case"syncing":return i("status.syncing","Syncing");case"initializing":return i("status.initializing","Initializing");case"error":return i("status.error","Error");default:return i("status.idle","Idle")}}function Je(e){switch(e){case"syncing":return"ok";case"initializing":return"warn";case"error":return"error";default:return"ok"}}function b(e,i,c,r){return t.jsxs("div",{className:e.metricSubtitle,children:[t.jsx(A,{label:i,tooltip:c}),": ",r]},i)}function d(e,i){return t.jsx(O,{text:i,children:e})}function st(){var w,B;const{t:e}=R(),{level:i,status:c,connectionInfo:r,syncStatus:a,changeSummary:n,recentChanges:l}=Xe(),m=q(c==null?void 0:c.uptime),g=t.jsx(U,{title:e("page.overview.title","Overview"),description:e("page.overview.description","Check server, plugin, agent, sync, and recent game-change status in one place."),helpTopicId:"overview",helpState:{connectionLevel:i}});if(i==="disconnected")return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.disconnectCard,children:[t.jsx("div",{className:s.disconnectIcon,children:"⚠️"}),t.jsx("h2",{className:s.disconnectTitle,children:e("overview.l0.title")}),t.jsx("p",{className:s.disconnectMessage,children:e("overview.l0.message")}),t.jsxs("div",{className:s.reconnectGuide,children:[t.jsxs("div",{className:s.guideStep,children:[t.jsx("span",{className:s.stepNumber,children:"1"}),t.jsx("span",{children:e("overview.l0.step1")})]}),t.jsxs("div",{className:s.guideStep,children:[t.jsx("span",{className:s.stepNumber,children:"2"}),t.jsx("span",{children:e("overview.l0.step2")})]})]}),t.jsxs("div",{className:s.reconnectIndicator,children:[t.jsx("span",{className:s.reconnectDot}),e("overview.l0.reconnecting")]}),t.jsxs("div",{className:s.disconnectActions,children:[t.jsx("button",{className:s.btn,onClick:()=>window.location.reload(),children:e("overview.l0.reconnectBtn")}),t.jsx("button",{className:s.btnSecondary,onClick:()=>{window.location.hash="#/settings"},children:e("overview.l0.settingsBtn")})]})]})]});const _=(r==null?void 0:r.mcpInstanceCount)??0,h=((w=r==null?void 0:r.mcpInstances)==null?void 0:w.find(I=>!I.isServer&&I.aiClientName))??((B=r==null?void 0:r.mcpInstances)==null?void 0:B.find(I=>!!I.aiClientName))??null,y=(c==null?void 0:c.pluginClients)??[],T=y.length>0,S=(c==null?void 0:c.sessionId)??(r==null?void 0:r.sessionId)??"-",f=e("overview.metric.server.tooltip","MCP server runtime and process status"),o=e("overview.metric.plugin.tooltip","Roblox Studio plugin connection and version status"),p=e("overview.metric.agent.tooltip","Connected AI coding agents and their runtime state"),x=e("overview.metric.sync.tooltip","Current Studio to local sync activity"),C=c?[b(s,e("overview.meta.version","Version"),e("overview.meta.version.tooltip","Installed MCP server version"),`v${c.version}`),b(s,e("overview.meta.session","Session"),e("overview.meta.session.tooltip","Current MCP session identifier"),S),b(s,e("overview.meta.pid","PID"),e("overview.meta.pid.tooltip","Operating system process identifier"),String(c.pid??"-")),b(s,e("overview.meta.uptime","Uptime"),e("overview.meta.uptime.tooltip","Time elapsed since the MCP server started"),J(m??c.uptime))]:[];if(i==="serverOnly")return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.metricRow,children:[t.jsx(N,{title:d(e("overview.metric.server"),f),value:d(e("status.online"),f),icon:"🖥️",status:"ok",children:t.jsxs(t.Fragment,{children:[C,t.jsx(z,{status:"online"})]})}),t.jsx(N,{title:d(e("overview.metric.agent"),p),value:d((h==null?void 0:h.aiClientName)??e("overview.metric.noAgent"),p),icon:"🤖",subtitle:_>1?`${_} ${e("overview.metric.agent.instancesUnit","instances")}`:void 0,status:h?"ok":"warn"})]}),t.jsxs("div",{className:s.guideCard,children:[t.jsx("h3",{className:s.guideTitle,children:e("overview.l1.pluginGuide")}),t.jsxs("ul",{className:s.checklist,children:[t.jsx("li",{children:e("overview.l1.check1")}),t.jsx("li",{children:e("overview.l1.check2")})]})]}),t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.feed.title")}),l.length>0?t.jsx(H,{changes:l}):t.jsx("div",{className:s.feedEmpty,children:e("overview.l1.feedHint")})]}),n&&D(n)>0&&t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.changelog.title")}),t.jsxs("div",{className:s.changelogSummary,children:[t.jsxs("span",{children:[e("overview.changelog.entries","Entries"),": ",D(n)]}),n.scriptsModified>0&&t.jsxs("span",{className:s.changeTag,children:["📝"," ",n.scriptsModified," ",e("overview.changelog.scripts")]}),n.instancesCreated>0&&t.jsxs("span",{className:s.changeTag,children:["🧱"," ",n.instancesCreated," ",e("overview.changelog.instances")]}),n.propertiesChanged>0&&t.jsxs("span",{className:s.changeTag,children:["🎨"," ",n.propertiesChanged," ",e("overview.changelog.properties")]}),n.assetsInserted>0&&t.jsxs("span",{className:s.changeTag,children:["📦"," ",n.assetsInserted," ",e("overview.changelog.assets")]})]})]})]});const u=y[0],j=n?D(n):0,k=!!n&&j>0;return t.jsxs("div",{className:s.page,children:[g,t.jsxs("div",{className:s.metricGrid,children:[t.jsx(N,{title:d(e("overview.metric.server"),f),value:d(e("status.online"),f),icon:"🖥️",status:"ok",children:t.jsx(t.Fragment,{children:C})}),t.jsx(N,{title:d(e("overview.metric.plugin"),o),value:d(e(T?"status.online":"status.offline"),o),icon:"🔌",subtitle:u?`${u.placeName??"-"} / v${u.pluginVersion??"-"}`:void 0,status:T?"ok":"error"}),t.jsx(N,{title:d(e("overview.metric.agent"),p),value:d((h==null?void 0:h.aiClientName)??e("overview.metric.noAgent"),p),icon:"🤖",subtitle:_>1?`${_} ${e("overview.metric.agent.instancesUnit","instances")}`:void 0,status:h?"ok":"warn"}),t.jsx(N,{title:d(e("overview.metric.sync"),x),value:d(qe(a==null?void 0:a.state,e),x),icon:"🔄",status:Je(a==null?void 0:a.state)})]}),t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.feed.title")}),t.jsx(H,{changes:l})]}),k&&t.jsxs("div",{className:s.card,children:[t.jsx("div",{className:s.cardHeader,children:e("overview.changelog.title")}),t.jsxs("div",{className:s.changelogSummary,children:[t.jsxs("span",{children:[e("overview.changelog.entries","Entries"),": ",j]}),n.scriptsModified>0&&t.jsxs("span",{className:s.changeTag,children:["📝"," ",n.scriptsModified," ",e("overview.changelog.scripts")]}),n.instancesCreated>0&&t.jsxs("span",{className:s.changeTag,children:["🧱"," ",n.instancesCreated," ",e("overview.changelog.instances")]}),n.propertiesChanged>0&&t.jsxs("span",{className:s.changeTag,children:["🎨"," ",n.propertiesChanged," ",e("overview.changelog.properties")]}),n.assetsInserted>0&&t.jsxs("span",{className:s.changeTag,children:["📦"," ",n.assetsInserted," ",e("overview.changelog.assets")]})]})]})]})}export{st as Component};