@weppy/roblox-mcp 2.0.9 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +39 -0
- package/README.md +11 -9
- package/docs/assets/screenshots/dashboard/dashboard_playtest.png +0 -0
- package/docs/assets/screenshots/plugin/sync/sync-overview.png +0 -0
- package/docs/en/dashboard/connection.md +1 -1
- package/docs/en/dashboard/overview.md +7 -7
- package/docs/en/dashboard/playtest.md +1 -1
- package/docs/en/dashboard/settings.md +1 -1
- package/docs/en/dashboard/sync.md +1 -1
- package/docs/en/dashboard/tools.md +1 -1
- package/docs/en/installation/README.md +1 -1
- package/docs/en/installation/roblox-explorer.md +2 -2
- package/docs/en/installation/roblox-plugin.md +4 -4
- package/docs/en/pro-upgrade.md +2 -2
- package/docs/en/sync/overview.md +3 -3
- package/docs/en/tools/playtest.md +2 -2
- package/docs/es/README.md +64 -12
- package/docs/es/dashboard/connection.md +1 -1
- package/docs/es/dashboard/overview.md +7 -7
- package/docs/es/dashboard/playtest.md +1 -1
- package/docs/es/dashboard/settings.md +1 -1
- package/docs/es/dashboard/sync.md +1 -1
- package/docs/es/dashboard/tools.md +1 -1
- package/docs/es/installation/README.md +1 -1
- package/docs/es/installation/roblox-explorer.md +2 -2
- package/docs/es/installation/roblox-plugin.md +4 -4
- package/docs/es/pro-upgrade.md +2 -2
- package/docs/es/sync/overview.md +3 -3
- package/docs/es/tools/playtest.md +2 -2
- package/docs/id/README.md +64 -12
- package/docs/id/dashboard/connection.md +1 -1
- package/docs/id/dashboard/overview.md +7 -7
- package/docs/id/dashboard/playtest.md +1 -1
- package/docs/id/dashboard/settings.md +1 -1
- package/docs/id/dashboard/sync.md +1 -1
- package/docs/id/dashboard/tools.md +1 -1
- package/docs/id/installation/README.md +1 -1
- package/docs/id/installation/roblox-explorer.md +2 -2
- package/docs/id/installation/roblox-plugin.md +4 -4
- package/docs/id/pro-upgrade.md +2 -2
- package/docs/id/sync/overview.md +3 -3
- package/docs/id/tools/playtest.md +2 -2
- package/docs/ja/README.md +64 -12
- package/docs/ja/dashboard/connection.md +1 -1
- package/docs/ja/dashboard/overview.md +7 -7
- package/docs/ja/dashboard/playtest.md +1 -1
- package/docs/ja/dashboard/settings.md +1 -1
- package/docs/ja/dashboard/sync.md +1 -1
- package/docs/ja/dashboard/tools.md +1 -1
- package/docs/ja/installation/README.md +1 -1
- package/docs/ja/installation/roblox-explorer.md +2 -2
- package/docs/ja/installation/roblox-plugin.md +4 -4
- package/docs/ja/pro-upgrade.md +2 -2
- package/docs/ja/sync/overview.md +3 -3
- package/docs/ja/tools/playtest.md +2 -2
- package/docs/ko/README.md +65 -13
- package/docs/ko/dashboard/connection.md +1 -1
- package/docs/ko/dashboard/overview.md +7 -7
- package/docs/ko/dashboard/playtest.md +1 -1
- package/docs/ko/dashboard/settings.md +1 -1
- package/docs/ko/dashboard/sync.md +1 -1
- package/docs/ko/dashboard/tools.md +1 -1
- package/docs/ko/installation/README.md +1 -1
- package/docs/ko/installation/roblox-explorer.md +2 -2
- package/docs/ko/installation/roblox-plugin.md +4 -4
- package/docs/ko/pro-upgrade.md +2 -2
- package/docs/ko/sync/overview.md +3 -3
- package/docs/ko/tools/playtest.md +2 -2
- package/docs/pt-br/README.md +64 -12
- package/docs/pt-br/dashboard/connection.md +1 -1
- package/docs/pt-br/dashboard/overview.md +7 -7
- package/docs/pt-br/dashboard/playtest.md +1 -1
- package/docs/pt-br/dashboard/settings.md +1 -1
- package/docs/pt-br/dashboard/sync.md +1 -1
- package/docs/pt-br/dashboard/tools.md +1 -1
- package/docs/pt-br/installation/README.md +1 -1
- package/docs/pt-br/installation/roblox-explorer.md +2 -2
- package/docs/pt-br/installation/roblox-plugin.md +4 -4
- package/docs/pt-br/pro-upgrade.md +2 -2
- package/docs/pt-br/sync/overview.md +3 -3
- package/docs/pt-br/tools/playtest.md +2 -2
- package/llms-full.txt +7 -7
- package/package.json +1 -1
- package/plugins/weppy-roblox-mcp/.claude-plugin/plugin.json +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ChangelogDetailPage-DRPIGDB0.js → ChangelogDetailPage-lzDR6yjY.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ChangelogPage-DVPYTw2L.js → ChangelogPage-BscI67Aj.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConfirmModal-BIJpNntn.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-CdLqNY4r.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{InfoLabel-DzXzzs6Q.js → InfoLabel-CBAqTqRy.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/OverviewPage-BOm0Ai9y.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{PlaytestPage-BjBAsHLz.js → PlaytestPage-DaDbQ6Qa.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{PropertyDiff-BZMdMzMr.js → PropertyDiff-D34Apw3G.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SettingsPage-yWzPPZIB.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{StatusBadge-DtcYlxe-.js → StatusBadge-B-pYMpUG.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SyncPage-E4XZhZn0.js +4 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{TierPromoProgress-r5fgmYI5.js → TierPromoProgress-CqxKoPOJ.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ToolsPage-Cfau3bX3.js → ToolsPage-yaahWgTq.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-DYnjsp-e.css +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-E1cuNPsJ.js +129 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{tier-promo-config-CQFDWwo4.js → tier-promo-config-BuGSENUv.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{useLiveUptime-5lD1XKnw.js → useLiveUptime-qJDofPOo.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/index.html +2 -2
- package/plugins/weppy-roblox-mcp/dist/index.js +61 -61
- package/plugins/weppy-roblox-mcp/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
- package/docs/assets/screenshots/connection_popup.png +0 -0
- package/docs/assets/screenshots/sync.png +0 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConfirmModal-Db4rfrTo.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConfirmModal-tvPLhSO9.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-Cv2i3LSr.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/OverviewPage-FoC28UL8.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SettingsPage-BKp2VKMW.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SyncPage-DcELF5_j.js +0 -4
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-BOVxaPTw.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-DWRH2iF4.js +0 -129
- /package/docs/assets/screenshots/{connection_guide.png → plugin/connection/connection-guide.png} +0 -0
- /package/docs/assets/screenshots/{plugin_main.png → plugin/installation/main-screen.png} +0 -0
- /package/docs/assets/screenshots/{plugins_menu.png → plugin/installation/plugins-menu.png} +0 -0
- /package/docs/assets/screenshots/{settings.png → plugin/installation/settings-screen.png} +0 -0
- /package/docs/assets/screenshots/{weppy_plugin_toolbar.png → plugin/installation/toolbar-button.png} +0 -0
- /package/docs/assets/screenshots/{license/license-dashboard.png → plugin/license/dashboard-license-screen.png} +0 -0
- /package/docs/assets/screenshots/{license/license-plugin.png → plugin/license/plugin-license-screen.png} +0 -0
- /package/docs/assets/screenshots/{sync_conflict.png → plugin/sync/sync-conflict.png} +0 -0
package/docs/pt-br/README.md
CHANGED
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
> **WROX** e um servidor MCP que permite agentes de codificacao IA controlarem uma sessao ao vivo do Roblox Studio — crie e edite scripts, instancias, terrain, iluminacao, assets, audio e animacoes com linguagem natural.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Ferramentas consolidadas baseadas em ações · Sync bidirecional · Playtest automatizado · Suporte multi-place**
|
|
6
6
|
|
|
7
7
|
[English](../../README.md) | [한국어](../ko/README.md) | [日本語](../ja/README.md) | [Español](../es/README.md) | **Português** | [Bahasa Indonesia](../id/README.md)
|
|
8
8
|
|
|
9
9
|
[](https://youtu.be/3jrUpBbZPaw)
|
|
10
10
|
|
|
11
|
+
## Por que WROX (Weppy Roblox MCP)?
|
|
12
|
+
|
|
13
|
+
Agentes de codificação IA como Claude, Codex e Gemini são poderosos — mas não conseguem ver nem modificar nada dentro do Roblox Studio. O DataModel, scripts, terrain e iluminação são todos invisíveis para ferramentas externas. Sem uma ponte, a IA só pode gerar trechos de código que você precisa colar manualmente.
|
|
14
|
+
|
|
15
|
+
**WROX** é uma ponte entre agentes de IA e o Roblox Studio. A IA cria e modifica diretamente instâncias, scripts, propriedades, terrain e mais dentro do Studio, e as alterações são refletidas imediatamente no Studio e no dashboard para que você possa **ver exatamente o que mudou**.
|
|
16
|
+
|
|
17
|
+
Sem necessidade de copiar e colar código. A IA trabalha e você confere os resultados.
|
|
18
|
+
|
|
11
19
|
## Instalacao rapida
|
|
12
20
|
|
|
13
21
|
**Instalacao em um comando** — Instala o servidor MCP, o plugin do Roblox Studio e registra nos apps de IA em um único passo:
|
|
@@ -52,14 +60,15 @@ npx -y @weppy/roblox-mcp
|
|
|
52
60
|
| Codex CLI | [Configuracao](installation/ai-apps/codex-cli.md) |
|
|
53
61
|
| Codex Desktop | [Configuracao](installation/ai-apps/codex-app.md) |
|
|
54
62
|
| Gemini CLI | [Configuracao](installation/ai-apps/gemini-cli.md) |
|
|
63
|
+
| Antigravity | [Configuracao](installation/ai-apps/antigravity.md) |
|
|
55
64
|
|
|
56
65
|
> Funciona com qualquer cliente MCP compativel. O comando do servidor e `npx -y @weppy/roblox-mcp`.
|
|
57
66
|
|
|
58
67
|
## Compatibilidade
|
|
59
68
|
|
|
60
|
-
| Claude Code | Claude Desktop | Cursor | Codex CLI | Gemini CLI |
|
|
61
|
-
|
|
62
|
-
| ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
69
|
+
| Claude Code | Claude Desktop | Cursor | Codex CLI | Gemini CLI | Antigravity |
|
|
70
|
+
|:-----------:|:--------------:|:------:|:---------:|:----------:|:-----------:|
|
|
71
|
+
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
63
72
|
|
|
64
73
|
**Requisitos:** Node.js 18+, Roblox Studio, Windows 10+ ou macOS 12+
|
|
65
74
|
|
|
@@ -73,17 +82,15 @@ A IA consegue operar diretamente scripts, instancias, propriedades, terreno, ilu
|
|
|
73
82
|
- "Cria uma arena de boss no centro do mapa e coloca spawns sem colisao."
|
|
74
83
|
- "Muda a interface deste modulo e atualiza todos os scripts dependentes."
|
|
75
84
|
|
|
76
|
-
Nao e apenas geracao de codigo. Sao **acoes executaveis para fluxo real de desenvolvimento**.
|
|
77
|
-
|
|
78
85
|
### 2) Sync: mantem contexto completo do projeto para a IA
|
|
79
86
|
|
|
80
87
|
A IA trabalha com um espelho local sincronizado, entao alteracoes em varios arquivos continuam consistentes.
|
|
81
88
|
|
|
82
|
-

|
|
83
|
-
|
|
84
89
|
- Basic: sincronizacao unidirecional (Studio -> Local)
|
|
85
90
|
- Pro: sincronizacao bidirecional + Direction/Apply Mode por tipo + historico + multiplace
|
|
86
91
|
|
|
92
|
+

|
|
93
|
+
|
|
87
94
|
### 3) Playtest: a IA executa e valida testes automaticamente
|
|
88
95
|
|
|
89
96
|
A IA pode controlar diretamente o playtest do Studio. Ela pode iniciar e parar Play (F5) ou Run (F8), injetar scripts de teste, coletar logs e gerar relatorios locais automaticamente.
|
|
@@ -92,28 +99,30 @@ A IA pode controlar diretamente o playtest do Studio. Ela pode iniciar e parar P
|
|
|
92
99
|
- "Escreva e execute um teste para confirmar que o SpawnLocation esta acima do chao."
|
|
93
100
|
- "Valide com playtest se o script que acabei de alterar roda sem erros."
|
|
94
101
|
|
|
102
|
+

|
|
103
|
+
|
|
95
104
|
### 4) WROX Dashboard: monitore as operacoes da IA em tempo real
|
|
96
105
|
|
|
97
106
|
No dashboard web fornecido pelo servidor MCP, acompanhe em tempo real o status de conexao, historico de execucao de ferramentas, status de sincronizacao e historico de alteracoes do jogo.
|
|
98
107
|
|
|
99
|
-

|
|
100
|
-
|
|
101
108
|
- Visualize o status de conexao do servidor/plugin/agente de uma so vez
|
|
102
109
|
- Compare todas as alteracoes feitas pela IA com Before & After no Changelog
|
|
103
110
|
- Analise o fluxo de trabalho com historico e estatisticas de execucao de ferramentas
|
|
104
111
|
|
|
112
|
+

|
|
113
|
+
|
|
105
114
|
### 5) WROX Roblox Explorer: navegue a hierarquia do Studio no VSCode
|
|
106
115
|
|
|
107
116
|
Visualize a arvore completa de instancias do seu lugar no Roblox Studio diretamente dentro do VSCode. Navegue pelos servicos, abra scripts e arquivos de propriedades sincronizados, e acompanhe o status de sincronizacao — tudo sem trocar para o Studio.
|
|
108
117
|
WROX Roblox Explorer e uma extensao complementar do VSCode para os dados de sync gerados pelo WROX. A navegacao basica da arvore funciona a partir dos arquivos sincronizados em disco, e os indicadores ao vivo de status sync ou direction ficam mais completos quando o servidor MCP local esta em execucao.
|
|
109
118
|
Instale pela [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=weppy.weppy-roblox-explorer) ou pela [Open VSX](https://open-vsx.org/extension/weppy/weppy-roblox-explorer).
|
|
110
119
|
|
|
111
|
-

|
|
112
|
-
|
|
113
120
|
- Icones de classe iguais ao Studio para reconhecimento imediato
|
|
114
121
|
- Clique para abrir scripts e arquivos de propriedades sincronizados
|
|
115
122
|
- Suporte multiplace com indicadores de status de sincronizacao
|
|
116
123
|
|
|
124
|
+

|
|
125
|
+
|
|
117
126
|
## Valor imediato para o usuario
|
|
118
127
|
|
|
119
128
|
- Comprimir trabalho repetitivo: transformar muitas edicoes manuais em um pedido
|
|
@@ -121,6 +130,14 @@ Instale pela [VS Code Marketplace](https://marketplace.visualstudio.com/items?it
|
|
|
121
130
|
- Reduzir risco: decidir com base no estado do sync e no historico
|
|
122
131
|
- Melhor eficiencia de tokens (Pro): menos round trips com acoes em massa
|
|
123
132
|
|
|
133
|
+
## Casos de uso
|
|
134
|
+
|
|
135
|
+
- **Prototipagem rápida**: Descreva uma mecânica de jogo em linguagem natural e veja a IA construí-la no Studio
|
|
136
|
+
- **Refatoração em massa**: Renomeie uma interface de módulo e atualize todos os scripts dependentes em uma única solicitação
|
|
137
|
+
- **Terrain e ambiente**: Gere terrain procedural, configure iluminação/atmosfera, posicione assets — tudo a partir de um único prompt
|
|
138
|
+
- **Consistência multi-arquivo**: A IA lê o projeto completo via Sync e aplica alterações em scripts relacionados de forma conjunta
|
|
139
|
+
- **Integração de assets**: Pesquise no Creator Store, insira modelos e configure propriedades sem sair do editor
|
|
140
|
+
|
|
124
141
|
## Documentacao detalhada
|
|
125
142
|
|
|
126
143
|
- [Guia de instalacao](installation/README.md)
|
|
@@ -140,12 +157,47 @@ Instale pela [VS Code Marketplace](https://marketplace.visualstudio.com/items?it
|
|
|
140
157
|
- [Playtest e testes automatizados](tools/playtest.md) - controle de playtest e validacao automatica
|
|
141
158
|
- [Sistema e depuracao](tools/system-and-debugging.md) - conexao, logs e execucao em lote
|
|
142
159
|
|
|
160
|
+
## FAQ
|
|
161
|
+
|
|
162
|
+
### Como conecto o Claude Code ao Roblox Studio?
|
|
163
|
+
Instale o plugin do Roblox Studio e registre o servidor MCP (`npx -y @weppy/roblox-mcp`) no Claude Code. O Claude poderá ler e escrever scripts diretamente dentro do Studio. Consulte [Configuração do Claude Code](installation/ai-apps/claude-code.md).
|
|
164
|
+
|
|
165
|
+
### Como uso o Codex CLI com o Roblox Studio?
|
|
166
|
+
Instale o plugin e adicione a configuração do servidor MCP ao Codex CLI. Consulte [Configuração do Codex CLI](installation/ai-apps/codex-cli.md).
|
|
167
|
+
|
|
168
|
+
### O Roblox MCP funciona com o Cursor?
|
|
169
|
+
Sim. Consulte [Configuração do Cursor](installation/ai-apps/cursor.md). Qualquer cliente de IA compatível com MCP funciona.
|
|
170
|
+
|
|
171
|
+
### A IA pode criar jogos Roblox com isso?
|
|
172
|
+
Sim. A IA pode criar instâncias, escrever scripts, gerar terrain, configurar iluminação, inserir assets, configurar física e mais — tudo dentro de uma sessão de Studio ao vivo. Vai além da geração de código para ações executáveis.
|
|
173
|
+
|
|
174
|
+
### Qual é a diferença entre Basic e Pro?
|
|
175
|
+
Basic (gratuito) inclui execução de ferramentas MCP e sincronização unidirecional (Studio -> Local). Pro adiciona sincronização bidirecional, operações em massa, geração de terrain, análise espacial, controle de áudio/animação e suporte multi-place. Consulte o [Guia de upgrade Pro](pro-upgrade.md).
|
|
176
|
+
|
|
177
|
+
### Como o Weppy se diferencia de outros servidores MCP para Roblox?
|
|
178
|
+
O Weppy usa despacho baseado em ações em vez de ferramentas separadas para cada função. Isso reduz significativamente o consumo de tokens de IA. Também fornece sincronização bidirecional de projeto e suporte multi-place, que a maioria das alternativas não possui.
|
|
179
|
+
|
|
180
|
+
### É seguro? A IA pode quebrar meu jogo?
|
|
181
|
+
O servidor roda apenas em localhost (127.0.0.1:3002). Caminhos proibidos (CoreGui, CorePackages) são bloqueados. Limitação de taxa (450 req/min) e timeouts de 30 segundos previnem operações descontroladas. Todas as alterações são rastreáveis pelo histórico de sincronização.
|
|
182
|
+
|
|
143
183
|
## Upgrade Pro
|
|
144
184
|
|
|
145
185
|
Sync bidirecional, recursos avancados de criacao e eficiencia de tokens de IA — tudo em uma unica atualizacao.
|
|
146
186
|
|
|
147
187
|
[Guia de upgrade Pro](pro-upgrade.md)
|
|
148
188
|
|
|
189
|
+
## Licença
|
|
190
|
+
|
|
191
|
+
Este repositório está licenciado sob `AGPL-3.0`.
|
|
192
|
+
|
|
193
|
+
Licenciamento comercial está disponível separadamente. Consulte [COMMERCIAL-LICENSE.md](../../COMMERCIAL-LICENSE.md).
|
|
194
|
+
|
|
195
|
+
O uso do nome e logotipos Weppy é regido por [TRADEMARKS.md](../../TRADEMARKS.md).
|
|
196
|
+
|
|
149
197
|
---
|
|
150
198
|
|
|
199
|
+
[](https://www.npmjs.com/package/@weppy/roblox-mcp) [](https://nodejs.org/) [](https://smithery.ai/server/@hope1026/weppy-roblox-mcp)
|
|
200
|
+
|
|
201
|
+
[](https://glama.ai/mcp/servers/hope1026/roblox-mcp)
|
|
202
|
+
|
|
151
203
|
[GitHub Issues](https://github.com/hope1026/weppy-roblox-mcp/issues) · [Discussions](https://github.com/hope1026/weppy-roblox-mcp/discussions) · [npm](https://www.npmjs.com/package/@weppy/roblox-mcp)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Visao geral
|
|
8
8
|
|
|
9
|
-
A pagina Connection monitora todos os status de conexao do sistema MCP em um unico local. Esta sempre acessivel quando o
|
|
9
|
+
A pagina Connection monitora todos os status de conexao do sistema MCP em um unico local. Esta sempre acessivel quando o dashboard esta em estado **Servidor conectado** ou **Studio conectado**.
|
|
10
10
|
|
|
11
11
|
## Server Status
|
|
12
12
|
|
|
@@ -34,17 +34,17 @@ http://localhost:3002
|
|
|
34
34
|
|
|
35
35
|
> Defina `DASHBOARD_AUTO_OPEN=false` para desativar a abertura automatica (consulte a pagina [Settings](settings.md)).
|
|
36
36
|
|
|
37
|
-
##
|
|
37
|
+
## Estados de conexao
|
|
38
38
|
|
|
39
39
|
O Dashboard oferece funcionalidades diferentes de acordo com o status da conexao:
|
|
40
40
|
|
|
41
|
-
|
|
|
42
|
-
|
|
43
|
-
| **
|
|
44
|
-
| **
|
|
45
|
-
| **
|
|
41
|
+
| Estado | Condicao | Paginas disponiveis |
|
|
42
|
+
|--------|----------|---------------------|
|
|
43
|
+
| **Servidor desconectado** | Servidor desconectado | Exibe apenas a tela de aguardando reconexao |
|
|
44
|
+
| **Servidor conectado** | Servidor conectado, plugin desconectado | Connection, Tools, Settings |
|
|
45
|
+
| **Studio conectado** | Servidor + plugin ambos conectados | Todas as paginas |
|
|
46
46
|
|
|
47
|
-
Quando o
|
|
47
|
+
Quando o dashboard esta em estado **Servidor conectado**, as paginas Overview, Changelog, Sync e Playtest nao ficam acessiveis.
|
|
48
48
|
|
|
49
49
|
## Overview
|
|
50
50
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Visao geral
|
|
8
8
|
|
|
9
|
-
A pagina Playtest exibe o status e os resultados dos playtests executados pela IA. So fica acessivel quando o
|
|
9
|
+
A pagina Playtest exibe o status e os resultados dos playtests executados pela IA. So fica acessivel quando o dashboard esta em estado **Studio conectado**.
|
|
10
10
|
|
|
11
11
|
## Playtest Status
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Visao geral
|
|
6
6
|
|
|
7
|
-
Na pagina Settings, voce pode verificar as informacoes de licenca e as configuracoes do servidor, alem de alterar algumas delas. Esta sempre acessivel quando o
|
|
7
|
+
Na pagina Settings, voce pode verificar as informacoes de licenca e as configuracoes do servidor, alem de alterar algumas delas. Esta sempre acessivel quando o dashboard esta em estado **Servidor conectado** ou **Studio conectado**.
|
|
8
8
|
|
|
9
9
|
## License (somente leitura)
|
|
10
10
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## Visao geral
|
|
10
10
|
|
|
11
|
-
A pagina Sync exibe visualmente o status atual e as configuracoes da sincronizacao Studio <-> arquivos locais. So fica acessivel quando o
|
|
11
|
+
A pagina Sync exibe visualmente o status atual e as configuracoes da sincronizacao Studio <-> arquivos locais. So fica acessivel quando o dashboard esta em estado **Studio conectado**.
|
|
12
12
|
|
|
13
13
|
## Sync Status
|
|
14
14
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Visao geral
|
|
8
8
|
|
|
9
|
-
A pagina Tools fornece o historico e as estatisticas das ferramentas MCP executadas pela IA. E composta por duas sub-abas: **History** e **Statistics**. Esta sempre acessivel quando o
|
|
9
|
+
A pagina Tools fornece o historico e as estatisticas das ferramentas MCP executadas pela IA. E composta por duas sub-abas: **History** e **Statistics**. Esta sempre acessivel quando o dashboard esta em estado **Servidor conectado** ou **Studio conectado**.
|
|
10
10
|
|
|
11
11
|
## Aba History
|
|
12
12
|
|
|
@@ -72,7 +72,7 @@ Registre o servidor MCP no seu app de IA. Funciona com qualquer app que suporte
|
|
|
72
72
|
## Opcional: Instalar WROX Roblox Explorer (Extensão VSCode)
|
|
73
73
|
|
|
74
74
|
Navegue pelas árvores de instâncias sincronizadas dentro do VSCode com ícones de classes Roblox.
|
|
75
|
-
Esta extensao opcional exige que a instalacao do Roblox MCP acima ja esteja concluida, porque o Explorer le os dados `
|
|
75
|
+
Esta extensao opcional exige que a instalacao do Roblox MCP acima ja esteja concluida, porque o Explorer le os dados de Sync em `wrox-project-sync` dentro da raiz do projeto.
|
|
76
76
|
|
|
77
77
|
👉 [Guia de instalação do WROX Roblox Explorer](roblox-explorer.md)
|
|
78
78
|
|
|
@@ -9,7 +9,7 @@ Esta é uma extensao complementar do WROX, e não uma integração Roblox indepe
|
|
|
9
9
|
|
|
10
10
|
- VSCode 1.85+
|
|
11
11
|
- [Roblox MCP](../../../README.md) instalado com Sync habilitado (Basic ou Pro)
|
|
12
|
-
- `
|
|
12
|
+
- O Sync ja gerou `wrox-project-sync/place_*/.sync-meta.json` na raiz do projeto
|
|
13
13
|
|
|
14
14
|
## Instalação
|
|
15
15
|
|
|
@@ -37,7 +37,7 @@ A navegação basica da arvore funciona a partir dos arquivos sincronizados em d
|
|
|
37
37
|
|
|
38
38
|
| Configuração | Padrão | Descrição |
|
|
39
39
|
|--------------|--------|-----------|
|
|
40
|
-
| `robloxExplorer.syncRoot` | `""` | Caminho absoluto para a raiz do `
|
|
40
|
+
| `robloxExplorer.syncRoot` | `""` | Caminho absoluto para a raiz do `wrox-project-sync`. Se estiver vazio, e detectado automaticamente. O WROX usa `{projectRoot}/wrox-project-sync`. |
|
|
41
41
|
| `robloxExplorer.hidePropsFiles` | `false` | Oculta arquivos de Sync (`.props.json`, `_tree.json`, `.value.json`) no explorador padrão do VSCode. |
|
|
42
42
|
| `robloxExplorer.autoRefresh` | `true` | Atualiza automaticamente a árvore quando os arquivos Sync mudam. |
|
|
43
43
|
| `robloxExplorer.showSyncStatus` | `true` | Exibe decorações de status Sync nos itens da árvore. |
|
|
@@ -18,7 +18,7 @@ Nota:
|
|
|
18
18
|
2. Clique na aba **Plugins**
|
|
19
19
|
3. Clique em **Plugins Folder**
|
|
20
20
|
|
|
21
|
-

|
|
22
22
|
|
|
23
23
|
4. **Copie** `WeppyRobloxMCP.rbxm` para a pasta de Plugins
|
|
24
24
|
5. **Reinicie o Roblox Studio**
|
|
@@ -27,7 +27,7 @@ Nota:
|
|
|
27
27
|
|
|
28
28
|
Apos reiniciar, o botao **WROX** aparecera na aba Plugins.
|
|
29
29
|
|
|
30
|
-

|
|
31
31
|
|
|
32
32
|
## 4. Conectar ao Agente de IA
|
|
33
33
|
|
|
@@ -52,13 +52,13 @@ O servidor MCP deve estar instalado. Complete primeiro o guia do seu app de IA:
|
|
|
52
52
|
3. Clique em **Connect**
|
|
53
53
|
4. Quando aparecer **"Connected"**, esta pronto
|
|
54
54
|
|
|
55
|
-

|
|
56
56
|
|
|
57
57
|
## 5. Configuracoes (Opcional)
|
|
58
58
|
|
|
59
59
|
Use o botao de configuracoes no canto superior direito.
|
|
60
60
|
|
|
61
|
-

|
|
61
|
+

|
|
62
62
|
|
|
63
63
|
- **Conexao Automatica**
|
|
64
64
|
- **Reconexao Automatica**
|
|
@@ -48,7 +48,7 @@ Você só precisa ativar a licença uma vez, no plugin ou no dashboard. As duas
|
|
|
48
48
|
5. Se o status não atualizar imediatamente, clique em **Refresh**.
|
|
49
49
|
6. Quando a ativação terminar, o status muda de Basic para Pro e os recursos Pro ficam disponíveis.
|
|
50
50
|
|
|
51
|
-

|
|
52
52
|
|
|
53
53
|
### Ativar no dashboard
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ Você só precisa ativar a licença uma vez, no plugin ou no dashboard. As duas
|
|
|
58
58
|
4. Clique em **Activate License** para ativar a licença.
|
|
59
59
|
5. Se necessário, use **Refresh License** para buscar o status mais recente.
|
|
60
60
|
|
|
61
|
-

|
|
62
62
|
|
|
63
63
|
### Depois da ativação
|
|
64
64
|
|
|
@@ -12,13 +12,13 @@ Sem Sync, a IA so enxerga trechos colados no chat. Com Sync ativo, ela trabalha
|
|
|
12
12
|
|
|
13
13
|
## Como funciona
|
|
14
14
|
|
|
15
|
-

|
|
15
|
+

|
|
16
16
|
|
|
17
17
|
1. Full Sync: espelho inicial da arvore/instancias do Studio para local
|
|
18
18
|
2. Incremental Sync: atualizacao continua das mudancas novas
|
|
19
19
|
3. Rastreamento de History/Status: ver o que mudou, quando e em qual direcao
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Os dados de Sync ficam em `{projectRoot}/wrox-project-sync/place_{placeId}/explorer`.
|
|
22
22
|
|
|
23
23
|
### Explorar dados sincronizados no VSCode
|
|
24
24
|
|
|
@@ -109,7 +109,7 @@ No Pro, voce controla Direction e Apply Mode por tipo.
|
|
|
109
109
|
|
|
110
110
|
Quando mudancas sao detectadas tanto no Studio quanto no local durante a sincronizacao bidirecional, um dialogo de resolucao de conflitos aparece.
|
|
111
111
|
|
|
112
|
-
](../../assets/screenshots/plugin/sync/sync-conflict.png)
|
|
113
113
|
|
|
114
114
|
- **Studio Priority**: sobrescrever usando o estado do Studio como fonte de verdade
|
|
115
115
|
- **Local Priority**: aplicar arquivos locais ao Studio
|
|
@@ -86,10 +86,10 @@ Edit --play--> Running --stop--> Edit
|
|
|
86
86
|
|
|
87
87
|
### 5. Escrita de relatorios
|
|
88
88
|
|
|
89
|
-
Os relatorios e logs sao gravados em
|
|
89
|
+
Os relatorios e logs sao gravados em `{projectRoot}/wrox-project-sync/place_XXXXX/tests/YYYYMMDD-HHmmss/`.
|
|
90
90
|
|
|
91
91
|
```text
|
|
92
|
-
|
|
92
|
+
{projectRoot}/wrox-project-sync/place_XXXXX/tests/YYYYMMDD-HHmmss/
|
|
93
93
|
├── test-report.md
|
|
94
94
|
└── test-log.txt
|
|
95
95
|
```
|
package/llms-full.txt
CHANGED
|
@@ -495,7 +495,7 @@ Without Sync, AI only sees snippets pasted into chat. With Sync enabled, AI work
|
|
|
495
495
|
2. Incremental Sync: continuous update of new changes
|
|
496
496
|
3. History/Status tracking: inspect what changed, when, and in which direction
|
|
497
497
|
|
|
498
|
-
|
|
498
|
+
Sync data is stored under `{projectRoot}/wrox-project-sync/place_{placeId}/explorer`.
|
|
499
499
|
|
|
500
500
|
## Sync Capabilities
|
|
501
501
|
|
|
@@ -565,13 +565,13 @@ Set `DASHBOARD_AUTO_OPEN=false` to disable automatic opening.
|
|
|
565
565
|
| **Tools** | Tool execution history, statistics, tier distribution |
|
|
566
566
|
| **Settings** | License, log level, sync settings, language |
|
|
567
567
|
|
|
568
|
-
## Connection
|
|
568
|
+
## Connection States
|
|
569
569
|
|
|
570
|
-
|
|
|
571
|
-
|
|
572
|
-
| **
|
|
573
|
-
| **
|
|
574
|
-
| **
|
|
570
|
+
| State | Condition | Available Pages |
|
|
571
|
+
|-------|-----------|-----------------|
|
|
572
|
+
| **Server disconnected** | Server not connected | Reconnection waiting screen only |
|
|
573
|
+
| **Server connected** | Server connected, plugin not connected | Connection, Tools, Settings |
|
|
574
|
+
| **Studio connected** | Both server and plugin connected | All pages |
|
|
575
575
|
|
|
576
576
|
## Overview Page
|
|
577
577
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weppy/roblox-mcp",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "MCP (Model Context Protocol) server for Roblox Studio integration - enables AI coding agents to interact with Roblox Studio in real-time",
|
|
5
5
|
"main": "plugins/weppy-roblox-mcp/dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r,a as R,u as M,b as B,c as D,j as e,T as m}from"./index-DWRH2iF4.js";import{I as V}from"./InfoLabel-DzXzzs6Q.js";import{D as F,P as G}from"./PropertyDiff-BZMdMzMr.js";function P(t){const s={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const l of t)switch(l.category){case"script":l.changeType==="create"?s.scriptsCreated++:s.scriptsModified++;break;case"instance":l.changeType==="create"?s.instancesCreated++:l.changeType==="delete"?s.instancesDeleted++:l.changeType==="move"&&s.instancesMoved++;break;case"property":s.propertiesChanged++;break;case"lighting":s.lightingChanged=!0;break;case"terrain":s.terrainChanged=!0;break;case"asset":s.assetsInserted++;break}return s}function U(t){const[s,l]=r.useState(""),[a,d]=r.useState(""),[u,q]=r.useState(),[w,y]=r.useState("completed"),[E,I]=r.useState([]),[O,L]=r.useState([]),[f,x]=r.useState([]),[p,j]=r.useState(),[_,b]=r.useState(),[v,S]=r.useState(),[C,N]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[T,g]=r.useState(!0),[k,h]=r.useState(null),i=r.useCallback(async()=>{if(t){g(!0),h(null);try{const[c,o]=await Promise.all([R.get(`/api/dashboard/changelog/${t}`),R.get(`/api/dashboard/changelog/${t}/changes`)]);l(c.entryId),d(c.startTime),q(c.endTime),y(c.status),I(c.entries),L(c.failures),j(c.contextSummary),b(c.replayMetadata),S(c.verificationSummary),x(o.changes),N(P(o.changes))}catch(c){h(c instanceof Error?c.message:"Failed to load changelog detail")}finally{g(!1)}}},[t]);return r.useEffect(()=>{i()},[i]),{entryId:s,startTime:a,endTime:u,status:w,entries:E,failures:O,changes:f,changeSummary:C,contextSummary:p,replayMetadata:_,verificationSummary:v,loading:T,error:k,refresh:i}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function H(t){return z[t]??"❓"}const J="_page_q2jbi_2",W="_header_q2jbi_10",Y="_backLink_q2jbi_16",Q="_headerTitle_q2jbi_29",X="_headerTime_q2jbi_37",Z="_statusActive_q2jbi_44",ee="_statusCompleted_q2jbi_49",te="_section_q2jbi_54",ne="_sectionTitle_q2jbi_61",ae="_summaryGrid_q2jbi_74",ie="_summaryCard_q2jbi_80",se="_summaryCardActive_q2jbi_94",ce="_summaryIcon_q2jbi_99",re="_summaryCount_q2jbi_105",oe="_summaryLabel_q2jbi_112",le="_contextGrid_q2jbi_121",de="_contextRow_q2jbi_127",me="_contextKey_q2jbi_133",ge="_contextValue_q2jbi_141",he="_timelineFilter_q2jbi_149",ue="_filterLabel_q2jbi_156",ye="_filterSelect_q2jbi_162",fe="_timeline_q2jbi_149",xe="_timelineEntry_q2jbi_182",pe="_timelineTime_q2jbi_199",je="_timelineIcon_q2jbi_207",_e="_timelineBody_q2jbi_212",be="_timelineSummary_q2jbi_217",ve="_timelineTarget_q2jbi_224",Se="_timelineConfidence_q2jbi_231",Ce="_confidenceExact_q2jbi_240",Ne="_confidencePartial_q2jbi_245",Te="_confidenceAfterOnly_q2jbi_250",ke="_confidenceIntentOnly_q2jbi_255",qe="_confidenceUnknown_q2jbi_260",we="_timelineExpanded_q2jbi_266",Ee="_empty_q2jbi_338",Ie="_loading_q2jbi_347",Oe="_error_q2jbi_356",n={page:J,header:W,backLink:Y,headerTitle:Q,headerTime:X,statusActive:Z,statusCompleted:ee,section:te,sectionTitle:ne,summaryGrid:ae,summaryCard:ie,summaryCardActive:se,summaryIcon:ce,summaryCount:re,summaryLabel:oe,contextGrid:le,contextRow:de,contextKey:me,contextValue:ge,timelineFilter:he,filterLabel:ue,filterSelect:ye,timeline:fe,timelineEntry:xe,timelineTime:pe,timelineIcon:je,timelineBody:_e,timelineSummary:be,timelineTarget:ve,timelineConfidence:Se,confidenceExact:Ce,confidencePartial:Ne,confidenceAfterOnly:Te,confidenceIntentOnly:ke,confidenceUnknown:qe,timelineExpanded:we,empty:Ee,loading:Ie,error:Oe},$=[{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 A(t){if(!t)return"--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}`}function Le(t){if(!t)return"--:--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}:${String(s.getSeconds()).padStart(2,"0")}`}function Ae(t,s){if(!t||!s)return"";const l=new Date(s).getTime()-new Date(t).getTime();return l<0?"":`${Math.round(l/6e4)}min`}function Ke(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 Re(t,s){switch(s){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 $e(t,s){switch(s){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 Fe(){var f,x,p,j,_,b,v,S,C,N,T,g,k,h;const{t}=M(),{id:s}=B(),l=D(),a=U(s),[d,u]=r.useState("all"),[q,w]=r.useState(null),y=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:()=>l("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const E=Ae(a.startTime,a.endTime),I=a.endTime?`${A(a.startTime)} → ${A(a.endTime)} (${E})`:`${A(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,O=!!((f=a.contextSummary)!=null&&f.intent||(x=a.contextSummary)!=null&&x.testScenario||(p=a.contextSummary)!=null&&p.expectedBehavior||(j=a.contextSummary)!=null&&j.observedBehavior),L=!!((_=a.verificationSummary)!=null&&_.label||(b=a.verificationSummary)!=null&&b.status||(v=a.verificationSummary)!=null&&v.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:I}),e.jsx(m,{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(m,{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:$.map(i=>{const c=a.changeSummary;let o;switch(i.key){case"script":o=c.scriptsModified+c.scriptsCreated;break;case"instance":o=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":o=c.propertiesChanged;break;case"lighting":o=c.lightingChanged?1:0;break;case"terrain":o=c.terrainChanged?1:0;break;case"asset":o=c.assetsInserted;break;default:o=0}const K=d===i.key;return e.jsxs("div",{className:`${n.summaryCard} ${K?n.summaryCardActive:""}`,onClick:()=>u(K?"all":i.key),children:[e.jsx("span",{className:n.summaryIcon,children:i.icon}),e.jsx("div",{className:n.summaryCount,children:o}),e.jsx("div",{className:n.summaryLabel,children:t(i.labelKey,i.key)})]},i.key)})})]}),O&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{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:[((S=a.contextSummary)==null?void 0:S.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})]}),((C=a.contextSummary)==null?void 0:C.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})]}),((N=a.contextSummary)==null?void 0:N.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})]}),((T=a.contextSummary)==null?void 0:T.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})]})]})]}),L&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{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:[((g=a.verificationSummary)==null?void 0:g.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})]}),((k=a.verificationSummary)==null?void 0:k.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})]}),((h=a.verificationSummary)==null?void 0:h.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(m,{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(V,{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:i=>u(i.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),$.map(i=>e.jsxs("option",{value:i.key,children:[i.icon," ",t(i.labelKey,i.key)]},i.key))]})]}),y.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:y.map((i,c)=>{const o=q===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>w(o?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Le(i.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:H(i.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[i.summary,e.jsx(m,{text:$e(t,i.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Ke(i.confidence)}`,children:Re(t,i.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:i.target})]})]}),o&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(Me,{change:i})})]},c)})})]})]})}function Me({change:t}){return t.category==="script"&&(t.before||t.after)?e.jsx(F,{before:t.before,after:t.after}):t.category==="property"?e.jsx(G,{before:t.before,after:t.after}):t.details?e.jsx("pre",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-secondary)",margin:0,whiteSpace:"pre-wrap",wordBreak:"break-all"},children:JSON.stringify(t.details,null,2)}):e.jsx("div",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-muted)"},children:t.target})}export{Fe as Component};
|
|
1
|
+
import{r,a as R,u as M,b as B,c as D,j as e,T as m}from"./index-E1cuNPsJ.js";import{I as V}from"./InfoLabel-CBAqTqRy.js";import{D as F,P as G}from"./PropertyDiff-D34Apw3G.js";function P(t){const s={scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0};for(const l of t)switch(l.category){case"script":l.changeType==="create"?s.scriptsCreated++:s.scriptsModified++;break;case"instance":l.changeType==="create"?s.instancesCreated++:l.changeType==="delete"?s.instancesDeleted++:l.changeType==="move"&&s.instancesMoved++;break;case"property":s.propertiesChanged++;break;case"lighting":s.lightingChanged=!0;break;case"terrain":s.terrainChanged=!0;break;case"asset":s.assetsInserted++;break}return s}function U(t){const[s,l]=r.useState(""),[a,d]=r.useState(""),[u,q]=r.useState(),[w,y]=r.useState("completed"),[E,I]=r.useState([]),[O,L]=r.useState([]),[f,x]=r.useState([]),[p,j]=r.useState(),[_,b]=r.useState(),[v,S]=r.useState(),[C,N]=r.useState({scriptsModified:0,scriptsCreated:0,instancesCreated:0,instancesDeleted:0,instancesMoved:0,propertiesChanged:0,lightingChanged:!1,terrainChanged:!1,assetsInserted:0}),[T,g]=r.useState(!0),[k,h]=r.useState(null),i=r.useCallback(async()=>{if(t){g(!0),h(null);try{const[c,o]=await Promise.all([R.get(`/api/dashboard/changelog/${t}`),R.get(`/api/dashboard/changelog/${t}/changes`)]);l(c.entryId),d(c.startTime),q(c.endTime),y(c.status),I(c.entries),L(c.failures),j(c.contextSummary),b(c.replayMetadata),S(c.verificationSummary),x(o.changes),N(P(o.changes))}catch(c){h(c instanceof Error?c.message:"Failed to load changelog detail")}finally{g(!1)}}},[t]);return r.useEffect(()=>{i()},[i]),{entryId:s,startTime:a,endTime:u,status:w,entries:E,failures:O,changes:f,changeSummary:C,contextSummary:p,replayMetadata:_,verificationSummary:v,loading:T,error:k,refresh:i}}const z={script:"📝",instance:"🧱",property:"🎨",lighting:"🌅",terrain:"⛰️",asset:"📦"};function H(t){return z[t]??"❓"}const J="_page_q2jbi_2",W="_header_q2jbi_10",Y="_backLink_q2jbi_16",Q="_headerTitle_q2jbi_29",X="_headerTime_q2jbi_37",Z="_statusActive_q2jbi_44",ee="_statusCompleted_q2jbi_49",te="_section_q2jbi_54",ne="_sectionTitle_q2jbi_61",ae="_summaryGrid_q2jbi_74",ie="_summaryCard_q2jbi_80",se="_summaryCardActive_q2jbi_94",ce="_summaryIcon_q2jbi_99",re="_summaryCount_q2jbi_105",oe="_summaryLabel_q2jbi_112",le="_contextGrid_q2jbi_121",de="_contextRow_q2jbi_127",me="_contextKey_q2jbi_133",ge="_contextValue_q2jbi_141",he="_timelineFilter_q2jbi_149",ue="_filterLabel_q2jbi_156",ye="_filterSelect_q2jbi_162",fe="_timeline_q2jbi_149",xe="_timelineEntry_q2jbi_182",pe="_timelineTime_q2jbi_199",je="_timelineIcon_q2jbi_207",_e="_timelineBody_q2jbi_212",be="_timelineSummary_q2jbi_217",ve="_timelineTarget_q2jbi_224",Se="_timelineConfidence_q2jbi_231",Ce="_confidenceExact_q2jbi_240",Ne="_confidencePartial_q2jbi_245",Te="_confidenceAfterOnly_q2jbi_250",ke="_confidenceIntentOnly_q2jbi_255",qe="_confidenceUnknown_q2jbi_260",we="_timelineExpanded_q2jbi_266",Ee="_empty_q2jbi_338",Ie="_loading_q2jbi_347",Oe="_error_q2jbi_356",n={page:J,header:W,backLink:Y,headerTitle:Q,headerTime:X,statusActive:Z,statusCompleted:ee,section:te,sectionTitle:ne,summaryGrid:ae,summaryCard:ie,summaryCardActive:se,summaryIcon:ce,summaryCount:re,summaryLabel:oe,contextGrid:le,contextRow:de,contextKey:me,contextValue:ge,timelineFilter:he,filterLabel:ue,filterSelect:ye,timeline:fe,timelineEntry:xe,timelineTime:pe,timelineIcon:je,timelineBody:_e,timelineSummary:be,timelineTarget:ve,timelineConfidence:Se,confidenceExact:Ce,confidencePartial:Ne,confidenceAfterOnly:Te,confidenceIntentOnly:ke,confidenceUnknown:qe,timelineExpanded:we,empty:Ee,loading:Ie,error:Oe},$=[{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 A(t){if(!t)return"--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}`}function Le(t){if(!t)return"--:--:--";const s=new Date(t);return`${String(s.getHours()).padStart(2,"0")}:${String(s.getMinutes()).padStart(2,"0")}:${String(s.getSeconds()).padStart(2,"0")}`}function Ae(t,s){if(!t||!s)return"";const l=new Date(s).getTime()-new Date(t).getTime();return l<0?"":`${Math.round(l/6e4)}min`}function Ke(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 Re(t,s){switch(s){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 $e(t,s){switch(s){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 Fe(){var f,x,p,j,_,b,v,S,C,N,T,g,k,h;const{t}=M(),{id:s}=B(),l=D(),a=U(s),[d,u]=r.useState("all"),[q,w]=r.useState(null),y=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:()=>l("/changelog"),children:["←"," ",t("changelog.detail.backToList","Back to list")]})]});const E=Ae(a.startTime,a.endTime),I=a.endTime?`${A(a.startTime)} → ${A(a.endTime)} (${E})`:`${A(a.startTime)} → ${t("changelog.card.inProgress","in progress")}`,O=!!((f=a.contextSummary)!=null&&f.intent||(x=a.contextSummary)!=null&&x.testScenario||(p=a.contextSummary)!=null&&p.expectedBehavior||(j=a.contextSummary)!=null&&j.observedBehavior),L=!!((_=a.verificationSummary)!=null&&_.label||(b=a.verificationSummary)!=null&&b.status||(v=a.verificationSummary)!=null&&v.testTimestamp);return e.jsxs("div",{className:n.page,children:[e.jsxs("div",{className:n.header,children:[e.jsxs("span",{className:n.backLink,onClick:()=>l("/changelog"),children:["←"," ",t("sidebar.changelog","Changelog")]}),e.jsx("span",{className:n.headerTitle,children:"|"}),e.jsx("span",{className:n.headerTime,children:I}),e.jsx(m,{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(m,{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:$.map(i=>{const c=a.changeSummary;let o;switch(i.key){case"script":o=c.scriptsModified+c.scriptsCreated;break;case"instance":o=c.instancesCreated+c.instancesDeleted+c.instancesMoved;break;case"property":o=c.propertiesChanged;break;case"lighting":o=c.lightingChanged?1:0;break;case"terrain":o=c.terrainChanged?1:0;break;case"asset":o=c.assetsInserted;break;default:o=0}const K=d===i.key;return e.jsxs("div",{className:`${n.summaryCard} ${K?n.summaryCardActive:""}`,onClick:()=>u(K?"all":i.key),children:[e.jsx("span",{className:n.summaryIcon,children:i.icon}),e.jsx("div",{className:n.summaryCount,children:o}),e.jsx("div",{className:n.summaryLabel,children:t(i.labelKey,i.key)})]},i.key)})})]}),O&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{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:[((S=a.contextSummary)==null?void 0:S.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})]}),((C=a.contextSummary)==null?void 0:C.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})]}),((N=a.contextSummary)==null?void 0:N.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})]}),((T=a.contextSummary)==null?void 0:T.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})]})]})]}),L&&e.jsxs("div",{className:n.section,children:[e.jsx("div",{className:n.sectionTitle,children:e.jsx(m,{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:[((g=a.verificationSummary)==null?void 0:g.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})]}),((k=a.verificationSummary)==null?void 0:k.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})]}),((h=a.verificationSummary)==null?void 0:h.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(m,{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(V,{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:i=>u(i.target.value),children:[e.jsx("option",{value:"all",children:t("tools.filter.all","All")}),$.map(i=>e.jsxs("option",{value:i.key,children:[i.icon," ",t(i.labelKey,i.key)]},i.key))]})]}),y.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:y.map((i,c)=>{const o=q===c;return e.jsxs("div",{children:[e.jsxs("div",{className:n.timelineEntry,onClick:()=>w(o?null:c),children:[e.jsx("span",{className:n.timelineTime,children:Le(i.timestamp)}),e.jsx("span",{className:n.timelineIcon,children:H(i.category)}),e.jsxs("div",{className:n.timelineBody,children:[e.jsxs("div",{className:n.timelineSummary,children:[i.summary,e.jsx(m,{text:$e(t,i.confidence),children:e.jsx("span",{className:`${n.timelineConfidence} ${Ke(i.confidence)}`,children:Re(t,i.confidence)})})]}),e.jsx("div",{className:n.timelineTarget,children:i.target})]})]}),o&&e.jsx("div",{className:n.timelineExpanded,children:e.jsx(Me,{change:i})})]},c)})})]})]})}function Me({change:t}){return t.category==="script"&&(t.before||t.after)?e.jsx(F,{before:t.before,after:t.after}):t.category==="property"?e.jsx(G,{before:t.before,after:t.after}):t.details?e.jsx("pre",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-secondary)",margin:0,whiteSpace:"pre-wrap",wordBreak:"break-all"},children:JSON.stringify(t.details,null,2)}):e.jsx("div",{style:{fontFamily:"var(--font-code)",fontSize:"11px",color:"var(--text-muted)"},children:t.target})}export{Fe as Component};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as i,a as P,D as O,u as D,j as e,T as I,c as V,i as U}from"./index-DWRH2iF4.js";import{C as G}from"./ConfirmModal-Db4rfrTo.js";import{u as H,T as Z,a as q}from"./tier-promo-config-CQFDWwo4.js";import{t as m}from"./TierPromo.module-BBX3CVXn.js";const z=10;function J(){const[t,p]=i.useState([]),[s,a]=i.useState(0),[u,f]=i.useState(!1),[r,v]=i.useState(!0),[l,C]=i.useState(0),[d,j]=i.useState("all"),b=i.useRef(null),x=i.useCallback(async(h,o)=>{v(!0);try{const S={limit:String(z),offset:String(h)};o!=="all"&&(S.status=o);const N=await P.get("/api/dashboard/changelog",S);p(N.entries),a(N.total),f(N.hasMore)}catch{p([]),a(0),f(!1)}finally{v(!1)}},[]),y=i.useCallback(()=>{x(l,d)},[x,l,d]),_=i.useCallback(async()=>{await P.post("/api/dashboard/changelog/clear"),p([]),a(0),f(!1)},[]);return i.useEffect(()=>{x(l,d)},[x,l,d]),i.useEffect(()=>{const h=new O;b.current=h,h.connect();const o=h.on("command",()=>{x(l,d)});return()=>{o(),h.disconnect(),b.current=null}},[x,l,d]),{entries:t,total:s,hasMore:u,loading:r,offset:l,statusFilter:d,setOffset:C,setStatusFilter:j,refresh:y,clear:_}}const K="_card_1n89u_2",Q="_header_1n89u_17",W="_statusBadge_1n89u_24",X="_statusDot_1n89u_35",Y="_active_1n89u_41",ee="_completed_1n89u_50",se="_timeRange_1n89u_58",te="_summaryList_1n89u_65",ae="_summaryItem_1n89u_71",ne="_summaryIcon_1n89u_80",oe="_summaryText_1n89u_86",ce="_progressBar_1n89u_91",ie="_progressFill_1n89u_99",re="_emptySummary_1n89u_112",le="_contextBlock_1n89u_120",de="_contextLabel_1n89u_129",ge="_contextValue_1n89u_137",n={card:K,header:Q,statusBadge:W,statusDot:X,active:Y,completed:ee,timeRange:se,summaryList:te,summaryItem:ae,summaryIcon:ne,summaryText:oe,progressBar:ce,progressFill:ie,emptySummary:re,contextBlock:le,contextLabel:de,contextValue:ge};function F(t){if(!t)return"--:--";const p=new Date(t);return`${String(p.getHours()).padStart(2,"0")}:${String(p.getMinutes()).padStart(2,"0")}`}function me({entry:t,onClick:p}){var S,N,k,B,L,w,A,M,R,E;const{t:s}=D(),a=t.changeSummary,u=t.status==="active",f=t.isBootstrapOnly===!0,r=[],v=a.scriptsModified+a.scriptsCreated;if(v>0){const g=[];a.scriptsModified>0&&g.push(`${a.scriptsModified} ${s("changelog.card.modified","modified")}`),a.scriptsCreated>0&&g.push(`${a.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${v} ${s("changelog.card.scripts","scripts")} ${g.join(", ")}`;r.push({icon:"📝",text:T,tooltip:s("changelog.card.scripts.tooltip","Script changes made in this session.")})}const l=a.instancesCreated+a.instancesDeleted+a.instancesMoved;if(l>0){const g=[];a.instancesCreated>0&&g.push(`${a.instancesCreated} ${s("changelog.card.created","created")}`),a.instancesDeleted>0&&g.push(`${a.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),a.instancesMoved>0&&g.push(`${a.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${l} ${s("changelog.card.instances","instances")} ${g.join(", ")}`;r.push({icon:"🧱",text:T,tooltip:s("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}a.propertiesChanged>0&&r.push({icon:"🎨",text:`${a.propertiesChanged} ${s("changelog.card.propertiesChanged","properties changed")}`,tooltip:s("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),a.lightingChanged&&r.push({icon:"🌅",text:s("changelog.card.lightingConfigured","Lighting configured"),tooltip:s("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),a.terrainChanged&&r.push({icon:"⛰️",text:s("changelog.card.terrainConfigured","Terrain configured"),tooltip:s("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),a.assetsInserted>0&&r.push({icon:"📦",text:`${a.assetsInserted} ${s("changelog.card.assetsInserted","assets inserted")}`,tooltip:s("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const C=F(t.startTime),d=u?s("changelog.card.inProgress","in progress"):t.endTime?F(t.endTime):"--:--",j=f?s("changelog.card.bootstrapStatus","Bootstrap"):u?s("changelog.card.active","Active"):s("changelog.card.completed","Completed"),b=f?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."),x=f?s("changelog.card.bootstrapSummary","Initial sync snapshot"):s("changelog.card.noChanges","No changes yet"),y=f?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."),_=(N=(S=t.contextSummary)==null?void 0:S.intent)==null?void 0:N.trim(),h=((w=(L=(B=(k=t.contextSummary)==null?void 0:k.affectedAreas)==null?void 0:B[0])==null?void 0:L.label)==null?void 0:w.trim())||((M=(A=t.contextSummary)==null?void 0:A.testScenario)==null?void 0:M.trim()),o=(E=(R=t.verificationSummary)==null?void 0:R.label)==null?void 0:E.trim();return e.jsxs("div",{className:n.card,onClick:p,children:[e.jsxs("div",{className:n.header,children:[e.jsx(I,{text:b,children:e.jsxs("span",{className:`${n.statusBadge} ${u?n.active:n.completed}`,children:[e.jsx("span",{className:n.statusDot}),j]})}),e.jsxs("span",{className:n.timeRange,children:[C,"~",d]})]}),e.jsx("div",{className:n.summaryList,children:r.length>0?r.map((g,T)=>e.jsxs("div",{className:n.summaryItem,children:[e.jsx("span",{className:n.summaryIcon,children:g.icon}),e.jsx(I,{text:g.tooltip,children:e.jsx("span",{className:n.summaryText,children:g.text})})]},T)):e.jsx(I,{text:y,children:e.jsx("span",{className:n.emptySummary,style:{display:"block"},children:x})})}),_&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:_})]}),!_&&h&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:n.contextValue,children:h})]}),o&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.verification","Verification")}),e.jsx("span",{className:n.contextValue,children:o})]}),u&&e.jsx("div",{className:n.progressBar,children:e.jsx("div",{className:n.progressFill})})]})}const he="_page_1srvj_2",pe="_limitNotice_1srvj_9",ue="_limitNoticeTitle_1srvj_18",fe="_limitNoticeText_1srvj_25",xe="_headerRow_1srvj_31",_e="_header_1srvj_31",ve="_clearButton_1srvj_48",je="_headerSub_1srvj_57",be="_filterTabs_1srvj_67",ye="_filterTab_1srvj_67",Ne="_filterTabActive_1srvj_90",Ce="_list_1srvj_96",Se="_empty_1srvj_103",Te="_loading_1srvj_112",$e="_pagination_1srvj_121",Ie="_pageInfo_1srvj_129",ke="_btn_1srvj_135",c={page:he,limitNotice:pe,limitNoticeTitle:ue,limitNoticeText:fe,headerRow:xe,header:_e,clearButton:ve,headerSub:je,filterTabs:be,filterTab:ye,filterTabActive:Ne,list:Ce,empty:Se,loading:Te,pagination:$e,pageInfo:Ie,btn:ke},$=10,Be=[{key:"all",label:"changelog.filter.all"},{key:"active",label:"changelog.filter.active"},{key:"completed",label:"changelog.filter.completed"}];function Re(){const{t}=D(),p=V(),s=J(),a=H(),{show:u}=U(),[f,r]=i.useState(!1),[v,l]=i.useState(!1),[C,d]=i.useState(!1),j=!a.loading&&a.tier==="basic",b=j?s.entries.slice(0,3):s.entries,x=!j&&s.total>$,y=b.length,_=s.total,h=async()=>{l(!0);try{await s.clear(),u(t("toast.clearSuccess","Cleared successfully"),"success"),r(!1)}catch{u(t("toast.clearFailed","Failed to clear data"),"error")}finally{l(!1)}};return e.jsxs("div",{className:c.page,children:[e.jsxs("div",{className:c.headerRow,children:[e.jsxs("h2",{className:c.header,children:[t("sidebar.changelog","Changelog"),e.jsx("span",{className:c.headerSub,children:t("changelog.subtitle","Game Change History")})]}),e.jsx("button",{className:c.clearButton,onClick:()=>r(!0),children:t("common.clear","Clear")})]}),e.jsx("div",{className:c.filterTabs,children:Be.map(o=>e.jsx("button",{className:`${c.filterTab} ${s.statusFilter===o.key?c.filterTabActive:""}`,onClick:()=>{s.setStatusFilter(o.key),s.setOffset(0)},children:t(o.label,o.key.charAt(0).toUpperCase()+o.key.slice(1))},o.key))}),s.loading&&s.entries.length===0&&e.jsx("div",{className:c.loading,children:t("common.loading","Loading...")}),!s.loading&&s.entries.length===0?e.jsx("div",{className:c.empty,children:t("changelog.empty","No changelog entries yet")}):e.jsx("div",{className:c.list,children:b.map(o=>e.jsx(me,{entry:o,onClick:()=>p(`/changelog/${o.entryId}`)},o.entryId))}),x&&e.jsxs("div",{className:c.pagination,children:[e.jsx("button",{className:c.btn,disabled:s.offset===0,onClick:()=>s.setOffset(Math.max(0,s.offset-$)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:c.pageInfo,children:[s.offset+1,"–",Math.min(s.offset+$,s.total)," / ",s.total]}),e.jsx("button",{className:c.btn,disabled:!s.hasMore,onClick:()=>s.setOffset(s.offset+$),children:t("tools.page.next","Next")})]}),j&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:c.limitNotice,children:[e.jsx("div",{className:c.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:c.limitNoticeText,children:t("changelog.basic.limit.body","Upgrade to Pro to browse the full changelog timeline for this place.")})]}),e.jsxs("div",{className:m.progressPromo,children:[e.jsxs("div",{className:m.progressMain,children:[e.jsxs("div",{className:m.progressLabel,children:[e.jsx("span",{children:t("changelog.basic.metricLabel","Visible Changelog / Total")}),e.jsxs("span",{children:[y," / ",_]})]}),e.jsx("div",{className:m.progressBar,children:e.jsx("div",{className:m.progressFill,style:{width:`${_>0?Math.min(y/_*100,100):0}%`}})}),e.jsxs("div",{className:m.progressLabel,children:[e.jsxs("span",{children:[y," ",t("changelog.basic.visible","visible")]}),e.jsxs("span",{children:[_," ",t("changelog.basic.total","total")]})]})]}),e.jsx("span",{className:m.progressText,children:t("tier.banner.save","Save AI tokens with Pro!")}),e.jsxs("div",{className:m.actions,children:[e.jsx("button",{className:`${m.btn} ${m.btnOutline}`,onClick:()=>d(!0),children:t("tier.compare","Basic vs Pro")}),e.jsx("a",{className:`${m.btn} ${m.btnPrimary}`,href:Z.changelog,target:"_blank",rel:"noreferrer",children:t("tier.upgrade","Upgrade to Pro")})]})]})]}),e.jsx(G,{open:f,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:v,onCancel:()=>!v&&r(!1),onConfirm:h}),C&&e.jsx(q,{onClose:()=>d(!1)})]})}export{Re as Component};
|
|
1
|
+
import{r as i,a as P,D as O,u as D,j as e,T as I,c as V,i as U}from"./index-E1cuNPsJ.js";import{C as G}from"./ConfirmModal-BIJpNntn.js";import{u as H,T as Z,a as q}from"./tier-promo-config-BuGSENUv.js";import{t as m}from"./TierPromo.module-BBX3CVXn.js";const z=10;function J(){const[t,p]=i.useState([]),[s,a]=i.useState(0),[u,f]=i.useState(!1),[r,v]=i.useState(!0),[l,C]=i.useState(0),[d,j]=i.useState("all"),b=i.useRef(null),x=i.useCallback(async(h,o)=>{v(!0);try{const S={limit:String(z),offset:String(h)};o!=="all"&&(S.status=o);const N=await P.get("/api/dashboard/changelog",S);p(N.entries),a(N.total),f(N.hasMore)}catch{p([]),a(0),f(!1)}finally{v(!1)}},[]),y=i.useCallback(()=>{x(l,d)},[x,l,d]),_=i.useCallback(async()=>{await P.post("/api/dashboard/changelog/clear"),p([]),a(0),f(!1)},[]);return i.useEffect(()=>{x(l,d)},[x,l,d]),i.useEffect(()=>{const h=new O;b.current=h,h.connect();const o=h.on("command",()=>{x(l,d)});return()=>{o(),h.disconnect(),b.current=null}},[x,l,d]),{entries:t,total:s,hasMore:u,loading:r,offset:l,statusFilter:d,setOffset:C,setStatusFilter:j,refresh:y,clear:_}}const K="_card_1n89u_2",Q="_header_1n89u_17",W="_statusBadge_1n89u_24",X="_statusDot_1n89u_35",Y="_active_1n89u_41",ee="_completed_1n89u_50",se="_timeRange_1n89u_58",te="_summaryList_1n89u_65",ae="_summaryItem_1n89u_71",ne="_summaryIcon_1n89u_80",oe="_summaryText_1n89u_86",ce="_progressBar_1n89u_91",ie="_progressFill_1n89u_99",re="_emptySummary_1n89u_112",le="_contextBlock_1n89u_120",de="_contextLabel_1n89u_129",ge="_contextValue_1n89u_137",n={card:K,header:Q,statusBadge:W,statusDot:X,active:Y,completed:ee,timeRange:se,summaryList:te,summaryItem:ae,summaryIcon:ne,summaryText:oe,progressBar:ce,progressFill:ie,emptySummary:re,contextBlock:le,contextLabel:de,contextValue:ge};function F(t){if(!t)return"--:--";const p=new Date(t);return`${String(p.getHours()).padStart(2,"0")}:${String(p.getMinutes()).padStart(2,"0")}`}function me({entry:t,onClick:p}){var S,N,k,B,L,w,A,M,R,E;const{t:s}=D(),a=t.changeSummary,u=t.status==="active",f=t.isBootstrapOnly===!0,r=[],v=a.scriptsModified+a.scriptsCreated;if(v>0){const g=[];a.scriptsModified>0&&g.push(`${a.scriptsModified} ${s("changelog.card.modified","modified")}`),a.scriptsCreated>0&&g.push(`${a.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${v} ${s("changelog.card.scripts","scripts")} ${g.join(", ")}`;r.push({icon:"📝",text:T,tooltip:s("changelog.card.scripts.tooltip","Script changes made in this session.")})}const l=a.instancesCreated+a.instancesDeleted+a.instancesMoved;if(l>0){const g=[];a.instancesCreated>0&&g.push(`${a.instancesCreated} ${s("changelog.card.created","created")}`),a.instancesDeleted>0&&g.push(`${a.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),a.instancesMoved>0&&g.push(`${a.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${l} ${s("changelog.card.instances","instances")} ${g.join(", ")}`;r.push({icon:"🧱",text:T,tooltip:s("changelog.card.instances.tooltip","Instance create, delete, move, or clone changes in this session.")})}a.propertiesChanged>0&&r.push({icon:"🎨",text:`${a.propertiesChanged} ${s("changelog.card.propertiesChanged","properties changed")}`,tooltip:s("changelog.card.propertiesChanged.tooltip","Property value changes recorded for this session.")}),a.lightingChanged&&r.push({icon:"🌅",text:s("changelog.card.lightingConfigured","Lighting configured"),tooltip:s("changelog.card.lightingConfigured.tooltip","Lighting or atmosphere settings changed in this session.")}),a.terrainChanged&&r.push({icon:"⛰️",text:s("changelog.card.terrainConfigured","Terrain configured"),tooltip:s("changelog.card.terrainConfigured.tooltip","Terrain data or terrain settings changed in this session.")}),a.assetsInserted>0&&r.push({icon:"📦",text:`${a.assetsInserted} ${s("changelog.card.assetsInserted","assets inserted")}`,tooltip:s("changelog.card.assetsInserted.tooltip","Assets inserted into the place during this session.")});const C=F(t.startTime),d=u?s("changelog.card.inProgress","in progress"):t.endTime?F(t.endTime):"--:--",j=f?s("changelog.card.bootstrapStatus","Bootstrap"):u?s("changelog.card.active","Active"):s("changelog.card.completed","Completed"),b=f?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."),x=f?s("changelog.card.bootstrapSummary","Initial sync snapshot"):s("changelog.card.noChanges","No changes yet"),y=f?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."),_=(N=(S=t.contextSummary)==null?void 0:S.intent)==null?void 0:N.trim(),h=((w=(L=(B=(k=t.contextSummary)==null?void 0:k.affectedAreas)==null?void 0:B[0])==null?void 0:L.label)==null?void 0:w.trim())||((M=(A=t.contextSummary)==null?void 0:A.testScenario)==null?void 0:M.trim()),o=(E=(R=t.verificationSummary)==null?void 0:R.label)==null?void 0:E.trim();return e.jsxs("div",{className:n.card,onClick:p,children:[e.jsxs("div",{className:n.header,children:[e.jsx(I,{text:b,children:e.jsxs("span",{className:`${n.statusBadge} ${u?n.active:n.completed}`,children:[e.jsx("span",{className:n.statusDot}),j]})}),e.jsxs("span",{className:n.timeRange,children:[C,"~",d]})]}),e.jsx("div",{className:n.summaryList,children:r.length>0?r.map((g,T)=>e.jsxs("div",{className:n.summaryItem,children:[e.jsx("span",{className:n.summaryIcon,children:g.icon}),e.jsx(I,{text:g.tooltip,children:e.jsx("span",{className:n.summaryText,children:g.text})})]},T)):e.jsx(I,{text:y,children:e.jsx("span",{className:n.emptySummary,style:{display:"block"},children:x})})}),_&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.sessionIntent","Session intent")}),e.jsx("span",{className:n.contextValue,children:_})]}),!_&&h&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.representativeArea","Representative area")}),e.jsx("span",{className:n.contextValue,children:h})]}),o&&e.jsxs("div",{className:n.contextBlock,children:[e.jsx("span",{className:n.contextLabel,children:s("changelog.card.verification","Verification")}),e.jsx("span",{className:n.contextValue,children:o})]}),u&&e.jsx("div",{className:n.progressBar,children:e.jsx("div",{className:n.progressFill})})]})}const he="_page_1srvj_2",pe="_limitNotice_1srvj_9",ue="_limitNoticeTitle_1srvj_18",fe="_limitNoticeText_1srvj_25",xe="_headerRow_1srvj_31",_e="_header_1srvj_31",ve="_clearButton_1srvj_48",je="_headerSub_1srvj_57",be="_filterTabs_1srvj_67",ye="_filterTab_1srvj_67",Ne="_filterTabActive_1srvj_90",Ce="_list_1srvj_96",Se="_empty_1srvj_103",Te="_loading_1srvj_112",$e="_pagination_1srvj_121",Ie="_pageInfo_1srvj_129",ke="_btn_1srvj_135",c={page:he,limitNotice:pe,limitNoticeTitle:ue,limitNoticeText:fe,headerRow:xe,header:_e,clearButton:ve,headerSub:je,filterTabs:be,filterTab:ye,filterTabActive:Ne,list:Ce,empty:Se,loading:Te,pagination:$e,pageInfo:Ie,btn:ke},$=10,Be=[{key:"all",label:"changelog.filter.all"},{key:"active",label:"changelog.filter.active"},{key:"completed",label:"changelog.filter.completed"}];function Re(){const{t}=D(),p=V(),s=J(),a=H(),{show:u}=U(),[f,r]=i.useState(!1),[v,l]=i.useState(!1),[C,d]=i.useState(!1),j=!a.loading&&a.tier==="basic",b=j?s.entries.slice(0,3):s.entries,x=!j&&s.total>$,y=b.length,_=s.total,h=async()=>{l(!0);try{await s.clear(),u(t("toast.clearSuccess","Cleared successfully"),"success"),r(!1)}catch{u(t("toast.clearFailed","Failed to clear data"),"error")}finally{l(!1)}};return e.jsxs("div",{className:c.page,children:[e.jsxs("div",{className:c.headerRow,children:[e.jsxs("h2",{className:c.header,children:[t("sidebar.changelog","Changelog"),e.jsx("span",{className:c.headerSub,children:t("changelog.subtitle","Game Change History")})]}),e.jsx("button",{className:c.clearButton,onClick:()=>r(!0),children:t("common.clear","Clear")})]}),e.jsx("div",{className:c.filterTabs,children:Be.map(o=>e.jsx("button",{className:`${c.filterTab} ${s.statusFilter===o.key?c.filterTabActive:""}`,onClick:()=>{s.setStatusFilter(o.key),s.setOffset(0)},children:t(o.label,o.key.charAt(0).toUpperCase()+o.key.slice(1))},o.key))}),s.loading&&s.entries.length===0&&e.jsx("div",{className:c.loading,children:t("common.loading","Loading...")}),!s.loading&&s.entries.length===0?e.jsx("div",{className:c.empty,children:t("changelog.empty","No changelog entries yet")}):e.jsx("div",{className:c.list,children:b.map(o=>e.jsx(me,{entry:o,onClick:()=>p(`/changelog/${o.entryId}`)},o.entryId))}),x&&e.jsxs("div",{className:c.pagination,children:[e.jsx("button",{className:c.btn,disabled:s.offset===0,onClick:()=>s.setOffset(Math.max(0,s.offset-$)),children:t("tools.page.prev","Prev")}),e.jsxs("span",{className:c.pageInfo,children:[s.offset+1,"–",Math.min(s.offset+$,s.total)," / ",s.total]}),e.jsx("button",{className:c.btn,disabled:!s.hasMore,onClick:()=>s.setOffset(s.offset+$),children:t("tools.page.next","Next")})]}),j&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:c.limitNotice,children:[e.jsx("div",{className:c.limitNoticeTitle,children:t("changelog.basic.limit.title","Basic preview shows the latest 3 sessions")}),e.jsx("div",{className:c.limitNoticeText,children:t("changelog.basic.limit.body","Upgrade to Pro to browse the full changelog timeline for this place.")})]}),e.jsxs("div",{className:m.progressPromo,children:[e.jsxs("div",{className:m.progressMain,children:[e.jsxs("div",{className:m.progressLabel,children:[e.jsx("span",{children:t("changelog.basic.metricLabel","Visible Changelog / Total")}),e.jsxs("span",{children:[y," / ",_]})]}),e.jsx("div",{className:m.progressBar,children:e.jsx("div",{className:m.progressFill,style:{width:`${_>0?Math.min(y/_*100,100):0}%`}})}),e.jsxs("div",{className:m.progressLabel,children:[e.jsxs("span",{children:[y," ",t("changelog.basic.visible","visible")]}),e.jsxs("span",{children:[_," ",t("changelog.basic.total","total")]})]})]}),e.jsx("span",{className:m.progressText,children:t("tier.banner.save","Save AI tokens with Pro!")}),e.jsxs("div",{className:m.actions,children:[e.jsx("button",{className:`${m.btn} ${m.btnOutline}`,onClick:()=>d(!0),children:t("tier.compare","Basic vs Pro")}),e.jsx("a",{className:`${m.btn} ${m.btnPrimary}`,href:Z.changelog,target:"_blank",rel:"noreferrer",children:t("tier.upgrade","Upgrade to Pro")})]})]})]}),e.jsx(G,{open:f,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:v,onCancel:()=>!v&&r(!1),onConfirm:h}),C&&e.jsx(q,{onClose:()=>d(!1)})]})}export{Re as Component};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as s,s as e}from"./index-E1cuNPsJ.js";function x({open:c,title:i,message:n,cancelLabel:t,confirmLabel:o,loading:a=!1,onCancel:l,onConfirm:r}){return c?s.jsx("div",{className:e.backdrop,onClick:a?void 0:l,children:s.jsxs("div",{className:e.modal,onClick:d=>d.stopPropagation(),children:[s.jsx("h2",{className:e.title,children:i}),s.jsx("p",{className:e.message,children:n}),s.jsxs("div",{className:e.actions,children:[s.jsx("button",{className:e.cancelButton,onClick:l,disabled:a,children:t}),s.jsx("button",{className:e.confirmButton,onClick:r,disabled:a,children:a?"...":o})]})]})}):null}export{x as C};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as $,r,j as e,d as R,a as N,D as I,i as L,T as M}from"./index-E1cuNPsJ.js";import{I as a}from"./InfoLabel-CBAqTqRy.js";import{S as A}from"./StatusBadge-B-pYMpUG.js";import{C as E}from"./ConfirmModal-BIJpNntn.js";import{u as P,f as k}from"./useLiveUptime-qJDofPOo.js";const T="_container_1h084_2",H="_entry_1h084_14",B="_timestamp_1h084_21",D="_message_1h084_27",F="_warn_1h084_34",U="_error_1h084_39",G="_empty_1h084_44",v={container:T,entry:H,timestamp:B,message:D,warn:F,error:U,empty:G};function O(n){const t=new Date(n);return Number.isNaN(t.getTime())?n:`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}function V({entries:n}){const{t}=$(),c=r.useRef(null);return r.useEffect(()=>{const l=c.current;l&&(l.scrollTop=l.scrollHeight)},[n.length]),e.jsx("div",{ref:c,className:v.container,children:n.length===0?e.jsx("div",{className:v.empty,children:t("connection.log.empty","No events yet")}):n.map((l,u)=>e.jsxs("div",{className:`${v.entry} ${l.type?v[l.type]:""}`,children:[e.jsx("span",{className:v.timestamp,children:O(l.timestamp)}),e.jsx("span",{className:v.message,children:l.message})]},u))})}const S=50;function q(){const n=new Date;return`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}function X(){const{level:n,status:t,error:c}=R(),[l,u]=r.useState(null),[y,h]=r.useState([]),g=r.useRef(null),_=r.useCallback((i,f)=>{h(d=>{const p=[...d,{timestamp:q(),message:i,type:f}];return p.length>S?p.slice(-S):p})},[]),x=r.useCallback(async()=>{try{const i=await N.get("/connection-info");u(i)}catch{u(null)}},[]),j=r.useCallback(async()=>{try{const i=await N.get("/api/dashboard/connection-log");h(i.entries??[])}catch{h([])}},[]),C=r.useCallback(async()=>{await N.post("/api/dashboard/connection-log/clear"),h([])},[]);return r.useEffect(()=>{n!=="disconnected"&&t&&x(),j()},[n,t,x,j]),r.useEffect(()=>{const i=new I;g.current=i,i.connect();const f=i.on("connection",p=>{const m=p,b=m.status==="connected"?"connected":"disconnected";_(`Plugin ${b} — ${m.clientId}`,m.status==="connected"?"info":"warn")}),d=i.on("mcp_status",p=>{const m=p,b=m.status==="registered"?"registered":"unregistered";_(`MCP ${b} — ${m.aiClientName}`,m.status==="registered"?"info":"warn"),x()});return()=>{f(),d(),i.disconnect(),g.current=null}},[_,x]),{status:t,connectionInfo:l,connectionLog:y,level:n,error:c,clearConnectionLog:C}}const z="_page_12byi_2",J="_card_12byi_10",K="_disabled_12byi_18",Q="_cardHeader_12byi_24",W="_clearButton_12byi_37",Y="_serverGrid_12byi_47",Z="_statusRow_12byi_65",ee="_table_12byi_79",ne="_toggleBtn_12byi_104",te="_disconnected_12byi_119",se="_disconnectedActions_12byi_136",ce="_btn_12byi_143",oe="_emptyRow_12byi_161",s={page:z,card:J,disabled:K,cardHeader:Q,clearButton:W,serverGrid:Y,statusRow:Z,table:ee,toggleBtn:ne,disconnected:te,disconnectedActions:se,btn:ce,emptyRow:oe};function w(n,t){const c=Math.max(0,Math.floor((Date.now()-n)/1e3));return c<60?`${c}${t("connection.time.secondsAgo","s ago")}`:c<3600?`${Math.floor(c/60)}${t("connection.time.minutesAgo","m ago")}`:`${Math.floor(c/3600)}${t("connection.time.hoursAgo","h ago")}`}function pe(){var b;const{t:n}=$(),{status:t,connectionInfo:c,connectionLog:l,level:u,clearConnectionLog:y}=X(),{show:h}=L(),[g,_]=r.useState(!0),[x,j]=r.useState(!1),[C,i]=r.useState(!1),f=P(t==null?void 0:t.uptime),d=u==="disconnected",p=d?"offline":"online",m=async()=>{i(!0);try{await y(),h(n("toast.clearSuccess","Cleared successfully"),"success"),j(!1)}catch{h(n("toast.clearFailed","Failed to clear data"),"error")}finally{i(!1)}};return e.jsxs("div",{className:s.page,children:[e.jsxs("div",{className:s.card,children:[e.jsx("div",{className:s.cardHeader,children:n("connection.server.title","Server Status")}),d?e.jsxs("div",{className:s.disconnected,children:[e.jsx("h3",{children:n("level.l0.title")}),e.jsx("p",{children:n("level.l0.message")}),e.jsx("p",{children:n("common.reconnecting")}),e.jsxs("div",{className:s.disconnectedActions,children:[e.jsx("button",{className:s.btn,onClick:()=>window.location.reload(),children:n("connection.reconnect","Reconnect")}),e.jsx("button",{className:s.btn,onClick:()=>{window.location.hash="#/settings"},children:n("connection.checkSettings","Check Settings")})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:s.statusRow,children:e.jsx(A,{status:p})}),e.jsxs("dl",{className:s.serverGrid,children:[(t==null?void 0:t.version)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:e.jsx(a,{label:n("connection.server.version","Version"),tooltip:n("connection.server.version.tooltip","Installed MCP server version")})}),e.jsx("dd",{children:e.jsx(M,{text:n("connection.server.version.tooltip","Installed MCP server version"),children:`v${t.version}`})})]}),(t==null?void 0:t.pid)!=null&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:e.jsx(a,{label:n("connection.server.pid","PID"),tooltip:n("connection.server.pid.tooltip","Operating system process identifier")})}),e.jsx("dd",{children:t.pid})]}),(t==null?void 0:t.uptime)!=null&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:e.jsx(a,{label:n("connection.server.uptime","Uptime"),tooltip:n("connection.server.uptime.tooltip","Time elapsed since the MCP server started")})}),e.jsx("dd",{children:k(f??t.uptime)})]}),(t==null?void 0:t.sessionId)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:e.jsx(a,{label:n("connection.server.session","Session"),tooltip:n("connection.server.session.tooltip","Current MCP session identifier")})}),e.jsx("dd",{children:t.sessionId.slice(0,8)})]}),(c==null?void 0:c.serverExecutable)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:e.jsx(a,{label:n("connection.server.exec","Exec"),tooltip:n("connection.server.exec.tooltip","Executable path used to launch the MCP server")})}),e.jsx("dd",{children:c.serverExecutable})]})]})]})]}),e.jsxs("div",{className:`${s.card} ${d?s.disabled:""}`,children:[e.jsxs("div",{className:s.cardHeader,children:[e.jsxs("span",{children:[n("connection.agents.title","AI Agents")," ","(",(c==null?void 0:c.mcpInstanceCount)??0,")"]}),e.jsx("button",{className:s.toggleBtn,onClick:()=>_(o=>!o),"aria-label":g?n("common.collapse","Collapse"):n("common.expand","Expand"),children:g?"▾":"▸"})]}),g&&e.jsxs("table",{className:s.table,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:n("connection.agents.name","Agent")}),e.jsx("th",{children:e.jsx(a,{label:n("connection.server.pid","PID"),tooltip:n("connection.server.pid.tooltip","Operating system process identifier")})}),e.jsx("th",{children:e.jsx(a,{label:n("connection.agents.projectRoot","Project Root"),tooltip:n("connection.agents.projectRoot.tooltip","Authoritative project root for sync ownership")})}),e.jsx("th",{children:n("connection.agents.connected","Connected")})]})}),e.jsx("tbody",{children:c!=null&&c.mcpInstances&&c.mcpInstances.length>0?c.mcpInstances.map(o=>e.jsxs("tr",{children:[e.jsx("td",{children:o.aiClientName??n("connection.agents.unknown","Unknown")}),e.jsx("td",{children:o.pid}),e.jsx("td",{children:o.projectRoot??o.cwd??n("connection.agents.projectRoot.unresolved","Unresolved")}),e.jsx("td",{children:w(o.connectedAt,n)})]},o.instanceId)):e.jsx("tr",{children:e.jsx("td",{colSpan:4,className:s.emptyRow,children:n("connection.agents.none","No agents connected")})})})]})]}),e.jsxs("div",{className:`${s.card} ${d?s.disabled:""}`,children:[e.jsxs("div",{className:s.cardHeader,children:[n("connection.plugins.title","Plugins")," ","(",((b=t==null?void 0:t.pluginClients)==null?void 0:b.length)??0,")"]}),e.jsxs("table",{className:s.table,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:n("connection.plugins.place","Place")}),e.jsx("th",{children:e.jsx(a,{label:n("connection.plugins.clientId","Client ID"),tooltip:n("connection.plugins.clientId.tooltip","Unique plugin client identifier for this Studio connection")})}),e.jsx("th",{children:e.jsx(a,{label:n("connection.plugins.lastSeen","Last Seen"),tooltip:n("connection.plugins.lastSeen.tooltip","Most recent heartbeat received from the plugin")})}),e.jsx("th",{children:e.jsx(a,{label:n("connection.plugins.version","Ver"),tooltip:n("connection.plugins.version.tooltip","Installed plugin version reported by Studio")})})]})}),e.jsx("tbody",{children:t!=null&&t.pluginClients&&t.pluginClients.length>0?t.pluginClients.map(o=>e.jsxs("tr",{children:[e.jsx("td",{children:o.placeName??o.projectName??"-"}),e.jsx("td",{children:o.clientId.slice(0,10)}),e.jsx("td",{children:w(o.lastSeen,n)}),e.jsx("td",{children:o.pluginVersion??"-"})]},o.clientId)):e.jsx("tr",{children:e.jsx("td",{colSpan:4,className:s.emptyRow,children:n("connection.plugins.none","No plugins connected")})})})]})]}),e.jsxs("div",{className:`${s.card} ${d?s.disabled:""}`,children:[e.jsxs("div",{className:s.cardHeader,children:[e.jsx("span",{children:n("connection.log.title","Connection Log")}),e.jsx("button",{className:s.clearButton,onClick:()=>j(!0),children:n("common.clear","Clear")})]}),e.jsx(V,{entries:l})]}),e.jsx(E,{open:x,title:n("connection.clear.title","Clear connection log?"),message:n("connection.clear.message","This permanently removes the stored connection log for the current project."),cancelLabel:n("common.cancel","Cancel"),confirmLabel:n("common.clear","Clear"),loading:C,onCancel:()=>!C&&j(!1),onConfirm:m})]})}export{pe as Component};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as r,m as e}from"./index-
|
|
1
|
+
import{j as r,m as e}from"./index-E1cuNPsJ.js";function s({label:t,tooltip:o}){return r.jsx(e,{text:o,children:t})}export{s as I};
|