@weppy/roblox-mcp 2.3.0 → 2.4.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/.github/workflows/install-test.yml +108 -0
- package/CHANGELOG.md +32 -0
- package/README.md +13 -7
- package/docs/en/installation/README.md +2 -2
- package/docs/en/installation/roblox-explorer.md +13 -3
- package/docs/en/installation/roblox-plugin.md +42 -31
- package/docs/en/pro-upgrade.md +26 -12
- package/docs/en/sync/luau-lsp.md +41 -0
- package/docs/en/sync/overview.md +4 -1
- package/docs/es/README.md +12 -4
- package/docs/es/installation/README.md +2 -2
- package/docs/es/pro-upgrade.md +26 -12
- package/docs/es/sync/luau-lsp.md +41 -0
- package/docs/es/sync/overview.md +4 -1
- package/docs/id/README.md +12 -4
- package/docs/id/installation/README.md +2 -2
- package/docs/id/pro-upgrade.md +26 -12
- package/docs/id/sync/luau-lsp.md +41 -0
- package/docs/id/sync/overview.md +4 -1
- package/docs/installer/assets/index-Bz0amd7x.js +63 -0
- package/docs/installer/assets/index-ei4lRUa6.css +1 -0
- package/docs/installer/index.html +2 -2
- package/docs/ja/README.md +14 -8
- package/docs/ja/installation/README.md +2 -2
- package/docs/ja/pro-upgrade.md +26 -12
- package/docs/ja/sync/luau-lsp.md +41 -0
- package/docs/ja/sync/overview.md +4 -1
- package/docs/ko/README.md +13 -7
- package/docs/ko/installation/README.md +2 -2
- package/docs/ko/installation/roblox-explorer.md +13 -3
- package/docs/ko/installation/roblox-plugin.md +42 -31
- package/docs/ko/pro-upgrade.md +26 -12
- package/docs/ko/sync/luau-lsp.md +41 -0
- package/docs/ko/sync/overview.md +4 -1
- package/docs/pt-br/README.md +12 -4
- package/docs/pt-br/installation/README.md +2 -2
- package/docs/pt-br/pro-upgrade.md +26 -12
- package/docs/pt-br/sync/luau-lsp.md +41 -0
- package/docs/pt-br/sync/overview.md +4 -1
- package/docs/troubleshooting.md +1 -1
- package/install.ps1 +36 -96
- package/install.sh +22 -67
- package/llms.txt +1 -1
- 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-CGK59Jsx.js → ChangelogDetailPage-CDMDeGei.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ChangelogPage-oNm6ratx.js → ChangelogPage-Uhx5ND-w.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{ConfirmModal-Dtak3Vnq.js → ConfirmModal-BHlbjwL7.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-9bG71eB1.css +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-VXh4Hc9N.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{InfoLabel-CLvjiyTG.js → InfoLabel-CGOLGj5z.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{OverviewPage-BdF0Ve7h.js → OverviewPage-CWnqw6VH.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{PlaytestPage-cQMWlAOS.js → PlaytestPage-62dIQkgo.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/PropertyDiff-DnLJY3ZB.js +6 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{SettingsPage-C-QX0AY-.js → SettingsPage-Bjr3d4mM.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{StatusBadge-A9U9m2LQ.js → StatusBadge-6VL6HJhv.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SyncPage-jdplS80I.js +4 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/TierComparison-7eRDwSAZ.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/TierPromoProgress-DFG_858F.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ToolsPage-B8iwhAW0.css +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ToolsPage-Cc6Vl-VU.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/WhatsNewPage-Lxgj0StO.css +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/WhatsNewPage-WPfXt13q.js +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-BhDELp5r.js +143 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-YfUJSF5s.css +1 -0
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/{useLiveUptime-Df1ECedb.js → useLiveUptime-BT-AiWEA.js} +1 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/index.html +2 -2
- package/plugins/weppy-roblox-mcp/dist/index.js +93 -81
- package/plugins/weppy-roblox-mcp/roblox-plugin/WeppyRobloxMCP.rbxm +0 -0
- package/docs/installer/assets/index-B4Gp7BPj.js +0 -63
- package/docs/installer/assets/index-B7mvmOPt.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-CN3LYLAT.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ConnectionPage-CjLtImxr.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/PropertyDiff-BnOZxkTS.js +0 -6
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/SyncPage-BAS0cXRM.js +0 -4
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/TierComparison-BA_L4c9p.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/TierPromoProgress-Dq6ofjr2.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ToolsPage-BZZZ3FXe.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/ToolsPage-C_tMIyix.js +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-DYnjsp-e.css +0 -1
- package/plugins/weppy-roblox-mcp/dashboard/dist/assets/index-OH9mpHwW.js +0 -129
|
@@ -25,9 +25,16 @@ A IA pode controlar os playtests do Roblox Studio diretamente. Ela pode iniciar
|
|
|
25
25
|
- "Escreve um teste que verifica se o SpawnLocation está acima do chão e executa."
|
|
26
26
|
- "Valida que o script que acabei de mudar funciona sem erros no playtest."
|
|
27
27
|
|
|
28
|
-
###
|
|
28
|
+
### Mais recursos exclusivos do Pro
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
O Pro desbloqueia recursos adicionais além do fluxo de trabalho principal.
|
|
31
|
+
|
|
32
|
+
- **Operações em massa** — Criar, modificar ou excluir múltiplas instâncias em uma única solicitação
|
|
33
|
+
- **Geração de terrain** — Preencher com bloco, esfera, cilindro, cunha e substituir materiais
|
|
34
|
+
- **Busca/inserção de assets** — Pesquisar no marketplace do Roblox e inserir assets diretamente
|
|
35
|
+
- **Análise espacial** — Raycast, encontrar chão, busca de área plana, detecção de colisão
|
|
36
|
+
- **Controle de ambiente** — Iluminação, atmosfera, céu e hora do dia
|
|
37
|
+
- **Áudio/Animação** — Reprodução de som e carregar/reproduzir animações
|
|
31
38
|
|
|
32
39
|
## Comprar e ativar
|
|
33
40
|
|
|
@@ -70,13 +77,20 @@ Você só precisa ativar a licença uma vez, no plugin ou no dashboard. As duas
|
|
|
70
77
|
|
|
71
78
|
| Recurso | Basic | Pro |
|
|
72
79
|
|---------|:-----:|:---:|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
80
|
+
| Criação/edição de scripts | ✅ | ✅ |
|
|
81
|
+
| Criar/excluir/mover instâncias | ✅ | ✅ + operações em massa |
|
|
82
|
+
| Ler/modificar propriedades | ✅ | ✅ + alterações em massa |
|
|
83
|
+
| Seleção, tags, busca | ✅ | ✅ |
|
|
84
|
+
| Controle de câmera | ✅ | ✅ |
|
|
85
|
+
| Monitoramento de logs | ✅ | ✅ |
|
|
86
|
+
| Execução de código Luau | ✅ | ✅ |
|
|
87
|
+
| Sincronização de projeto | Studio → Local unidirecional | Bidirecional + direção/modo por tipo |
|
|
88
|
+
| Sync multi-place | — | Até 3 Places simultaneamente |
|
|
89
|
+
| Histórico de mudanças | — | Rastrear mudanças antes de aplicar |
|
|
90
|
+
| Controle de playtest | — | Reproduzir / parar / pausar / retomar + testes automáticos |
|
|
91
|
+
| Geração/edição de terrain | — | Bloco, esfera, cilindro, cunha, substituição de material |
|
|
92
|
+
| Busca/inserção de assets | — | Pesquisar no marketplace do Roblox e inserir diretamente |
|
|
93
|
+
| Análise espacial | — | Raycast, encontrar chão, detecção de colisão |
|
|
94
|
+
| Controle de ambiente | — | Iluminação, atmosfera, céu, hora do dia |
|
|
95
|
+
| Áudio / Animação | — | Reprodução de som, carregar/reproduzir animações |
|
|
96
|
+
| Eficiência de tokens IA | Ações individuais | Menos chamadas com ações em massa |
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Usar `luau-lsp` com WROX Sync
|
|
2
|
+
|
|
3
|
+
O WROX Sync pode gerar automaticamente os arquivos sourcemap que o `luau-lsp` precisa, para que voce habilite recursos de editor com contexto de Roblox sem montar um projeto Rojo separado.
|
|
4
|
+
|
|
5
|
+
## O que o WROX grava
|
|
6
|
+
|
|
7
|
+
Depois que o Full Sync termina, o WROX grava:
|
|
8
|
+
|
|
9
|
+
- Place sourcemap: `wrox-project-sync/place_<id>/sourcemap.json`
|
|
10
|
+
- Arquivo representativo da raiz: `wrox-project-sync/sourcemap.json`
|
|
11
|
+
|
|
12
|
+
Para a maioria dos usuarios, o caminho recomendado e `wrox-project-sync/sourcemap.json`.
|
|
13
|
+
|
|
14
|
+
## O que melhora
|
|
15
|
+
|
|
16
|
+
Quando o `luau-lsp` usa o sourcemap do WROX, melhora:
|
|
17
|
+
|
|
18
|
+
- Autocomplete de `game.*`
|
|
19
|
+
- Navegacao entre scripts sincronizados
|
|
20
|
+
- Resolucao de `require` entre scripts sincronizados
|
|
21
|
+
|
|
22
|
+
## Configuracao recomendada
|
|
23
|
+
|
|
24
|
+
1. Execute o Full Sync uma vez para que o WROX crie `wrox-project-sync/sourcemap.json`.
|
|
25
|
+
2. Aponte a configuracao de sourcemap do `luau-lsp` no seu editor para `wrox-project-sync/sourcemap.json`.
|
|
26
|
+
3. Se o seu cliente puder desativar a geracao automatica com Rojo, defina `luau-lsp.sourcemap.autogenerate` como `false`.
|
|
27
|
+
|
|
28
|
+
Exemplo de configuracao no VSCode:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"luau-lsp.sourcemap.enabled": true,
|
|
33
|
+
"luau-lsp.sourcemap.autogenerate": false,
|
|
34
|
+
"luau-lsp.sourcemap.sourcemapFile": "wrox-project-sync/sourcemap.json"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Observacao sobre Multi-place
|
|
39
|
+
|
|
40
|
+
`wrox-project-sync/sourcemap.json` acompanha o place representativo atual do projeto.
|
|
41
|
+
Se voce precisar fixar um place especifico, aponte o `luau-lsp` diretamente para `wrox-project-sync/place_<id>/sourcemap.json`.
|
|
@@ -19,6 +19,8 @@ Sem Sync, a IA so enxerga trechos colados no chat. Com Sync ativo, ela trabalha
|
|
|
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
|
+
Alem disso, o WROX grava um sourcemap por place em `{projectRoot}/wrox-project-sync/place_{placeId}/sourcemap.json` e mantem o arquivo representativo recomendado na raiz em `{projectRoot}/wrox-project-sync/sourcemap.json`.
|
|
23
|
+
Para integracoes de editor como `luau-lsp`, o caminho da raiz e o recomendado. Os passos de configuracao estao em [Usar `luau-lsp` com WROX Sync](./luau-lsp.md).
|
|
22
24
|
|
|
23
25
|
### Explorar dados sincronizados no VSCode
|
|
24
26
|
|
|
@@ -146,5 +148,6 @@ Nomes que contem `~` sao escapados como `~~` (ex: `Part~2` → `Part~~2/`). Regr
|
|
|
146
148
|
|
|
147
149
|
## Documentos relacionados
|
|
148
150
|
|
|
151
|
+
- [Usar `luau-lsp` com WROX Sync](./luau-lsp.md)
|
|
149
152
|
- [Cobertura de ferramentas (Tools Overview)](../tools/overview.md)
|
|
150
|
-
- [Guia de upgrade Pro](
|
|
153
|
+
- [Guia de upgrade Pro](https://weppyai.com/en/plans)
|
package/docs/troubleshooting.md
CHANGED
package/install.ps1
CHANGED
|
@@ -4,17 +4,15 @@
|
|
|
4
4
|
# Usage:
|
|
5
5
|
# irm https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.ps1 | iex
|
|
6
6
|
#
|
|
7
|
-
# Interactive
|
|
8
|
-
# [1/
|
|
9
|
-
# [2/
|
|
10
|
-
# [3/3] Register MCP with AI apps (user selection)
|
|
7
|
+
# Interactive 2 steps:
|
|
8
|
+
# [1/2] Setup — install Roblox Studio Plugin via npx
|
|
9
|
+
# [2/2] Register MCP with AI apps (user selection)
|
|
11
10
|
#
|
|
12
11
|
|
|
13
12
|
$ErrorActionPreference = "Stop"
|
|
14
13
|
$script:InstallLogPath = Join-Path ([System.IO.Path]::GetTempPath()) ("wrox-install-{0:yyyyMMdd-HHmmss}.log" -f (Get-Date))
|
|
15
14
|
$script:TranscriptStarted = $false
|
|
16
15
|
$script:NpmCommandPath = $null
|
|
17
|
-
$script:NpmGlobalPrefix = $null
|
|
18
16
|
|
|
19
17
|
# ── Utilities ──
|
|
20
18
|
function Write-Step($step, $msg) { Write-Host "`n[$step] $msg" -ForegroundColor Cyan -NoNewline; Write-Host "" }
|
|
@@ -50,6 +48,10 @@ trap {
|
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
function Confirm-Action($prompt) {
|
|
51
|
+
if ($env:CI -eq 'true') {
|
|
52
|
+
Write-Host "$prompt (Y/n): Y"
|
|
53
|
+
return $true
|
|
54
|
+
}
|
|
53
55
|
$reply = Read-Host "$prompt (Y/n)"
|
|
54
56
|
if ([string]::IsNullOrWhiteSpace($reply)) { $reply = "Y" }
|
|
55
57
|
return $reply -match '^[Yy]'
|
|
@@ -69,30 +71,6 @@ function Resolve-NpmCommand() {
|
|
|
69
71
|
return $script:NpmCommandPath
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
function Get-NpmGlobalPrefix() {
|
|
73
|
-
if ($script:NpmGlobalPrefix) {
|
|
74
|
-
return $script:NpmGlobalPrefix
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
$script:NpmGlobalPrefix = (Invoke-Npm prefix -g 2>$null | Out-String).Trim()
|
|
78
|
-
return $script:NpmGlobalPrefix
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function Invoke-Npm {
|
|
82
|
-
param(
|
|
83
|
-
[Parameter(ValueFromRemainingArguments = $true)]
|
|
84
|
-
[string[]]$Args
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
$npmCommandPath = Resolve-NpmCommand
|
|
88
|
-
$output = & $npmCommandPath @Args
|
|
89
|
-
if ($LASTEXITCODE -ne 0) {
|
|
90
|
-
throw "npm $($Args -join ' ') failed with exit code $LASTEXITCODE"
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return $output
|
|
94
|
-
}
|
|
95
|
-
|
|
96
74
|
function Resolve-OptionalCliCommand($commandName) {
|
|
97
75
|
$resolvedCommand = Get-Command $commandName -ErrorAction SilentlyContinue
|
|
98
76
|
if ($resolvedCommand) {
|
|
@@ -100,11 +78,6 @@ function Resolve-OptionalCliCommand($commandName) {
|
|
|
100
78
|
}
|
|
101
79
|
|
|
102
80
|
$candidatePaths = @()
|
|
103
|
-
$npmPrefix = Get-NpmGlobalPrefix
|
|
104
|
-
if ($npmPrefix) {
|
|
105
|
-
$candidatePaths += (Join-Path $npmPrefix "$commandName.cmd")
|
|
106
|
-
$candidatePaths += (Join-Path $npmPrefix $commandName)
|
|
107
|
-
}
|
|
108
81
|
|
|
109
82
|
if ($env:APPDATA) {
|
|
110
83
|
$appDataNpmDir = Join-Path $env:APPDATA 'npm'
|
|
@@ -195,7 +168,7 @@ function Test-CodexConfigConfigured($configPath) {
|
|
|
195
168
|
|
|
196
169
|
$env:MCP_CODEX_CONFIG_PATH = $configPath
|
|
197
170
|
try {
|
|
198
|
-
node -e @
|
|
171
|
+
node -e @'
|
|
199
172
|
const fs = require('fs');
|
|
200
173
|
|
|
201
174
|
const configPath = process.env.MCP_CODEX_CONFIG_PATH;
|
|
@@ -602,7 +575,7 @@ try {
|
|
|
602
575
|
} catch {
|
|
603
576
|
process.exit(1);
|
|
604
577
|
}
|
|
605
|
-
|
|
578
|
+
'@
|
|
606
579
|
return $LASTEXITCODE -eq 0
|
|
607
580
|
}
|
|
608
581
|
finally {
|
|
@@ -630,11 +603,6 @@ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
|
630
603
|
}
|
|
631
604
|
}
|
|
632
605
|
|
|
633
|
-
function Test-LfsPointer($filePath) {
|
|
634
|
-
if (-not (Test-Path $filePath)) { return $false }
|
|
635
|
-
return Select-String -Path $filePath -Pattern "git-lfs.github.com/spec/v1" -Quiet
|
|
636
|
-
}
|
|
637
|
-
|
|
638
606
|
# ── Header ──
|
|
639
607
|
Write-Host ""
|
|
640
608
|
Write-Host "WROX Installer" -ForegroundColor White -BackgroundColor DarkCyan
|
|
@@ -655,71 +623,37 @@ catch {
|
|
|
655
623
|
}
|
|
656
624
|
|
|
657
625
|
# ═══════════════════════════════════
|
|
658
|
-
# [1/
|
|
626
|
+
# [1/2] Setup — Roblox Studio Plugin
|
|
659
627
|
# ═══════════════════════════════════
|
|
660
|
-
Write-Step "1/
|
|
628
|
+
Write-Step "1/2" "Setup Roblox Studio Plugin"
|
|
661
629
|
|
|
662
|
-
if (Confirm-Action " Run
|
|
630
|
+
if (Confirm-Action " Run npx -y @weppy/roblox-mcp --setup?") {
|
|
663
631
|
try {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
# ═══════════════════════════════════
|
|
676
|
-
# [2/3] Roblox Studio Plugin install
|
|
677
|
-
# ═══════════════════════════════════
|
|
678
|
-
Write-Step "2/3" "Install Roblox Studio Plugin"
|
|
679
|
-
|
|
680
|
-
$pluginsDir = Join-Path $env:LOCALAPPDATA "Roblox\Plugins"
|
|
681
|
-
$pluginName = "WeppyRobloxMCP.rbxm"
|
|
682
|
-
|
|
683
|
-
# Search for .rbxm in npm global path
|
|
684
|
-
$npmPrefix = Get-NpmGlobalPrefix
|
|
685
|
-
$bundledPlugin = $null
|
|
686
|
-
$searchPaths = @(
|
|
687
|
-
(Join-Path $npmPrefix "node_modules\@weppy\roblox-mcp\plugins\weppy-roblox-mcp\roblox-plugin\$pluginName"),
|
|
688
|
-
(Join-Path $npmPrefix "node_modules\@weppy\roblox-mcp\roblox-plugin\$pluginName")
|
|
689
|
-
)
|
|
690
|
-
foreach ($p in $searchPaths) {
|
|
691
|
-
if (Test-Path $p) {
|
|
692
|
-
$bundledPlugin = $p
|
|
693
|
-
break
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
if ($bundledPlugin) {
|
|
698
|
-
if (Test-LfsPointer $bundledPlugin) {
|
|
699
|
-
Abort-Install "Bundled plugin payload is invalid (Git LFS pointer detected). Install the plugin from the GitHub release ZIP instead."
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
Write-Host " → $pluginsDir\$pluginName"
|
|
703
|
-
if (Confirm-Action " Copy plugin to Roblox Plugins folder?") {
|
|
704
|
-
if (-not (Test-Path $pluginsDir)) {
|
|
705
|
-
New-Item -ItemType Directory -Path $pluginsDir -Force | Out-Null
|
|
632
|
+
$npmCommandPath = Resolve-NpmCommand
|
|
633
|
+
$npmDir = Split-Path $npmCommandPath -Parent
|
|
634
|
+
$npxPath = Join-Path $npmDir "npx.cmd"
|
|
635
|
+
if (-not (Test-Path $npxPath)) {
|
|
636
|
+
$npxPath = "npx"
|
|
637
|
+
}
|
|
638
|
+
& $npxPath -y "@weppy/roblox-mcp" --setup
|
|
639
|
+
if ($LASTEXITCODE -ne 0) {
|
|
640
|
+
Write-Warn "Setup encountered a warning (non-blocking)"
|
|
641
|
+
} else {
|
|
642
|
+
Write-Ok "Setup complete"
|
|
706
643
|
}
|
|
707
|
-
Copy-Item $bundledPlugin -Destination (Join-Path $pluginsDir $pluginName) -Force
|
|
708
|
-
Write-Ok "Plugin installed → $pluginsDir\$pluginName"
|
|
709
644
|
}
|
|
710
|
-
|
|
711
|
-
Write-Warn "
|
|
645
|
+
catch {
|
|
646
|
+
Write-Warn "Setup encountered a warning: $_"
|
|
712
647
|
}
|
|
713
648
|
}
|
|
714
649
|
else {
|
|
715
|
-
Write-Warn "
|
|
716
|
-
Write-Info "Will be installed automatically on first MCP server run"
|
|
650
|
+
Write-Warn "Setup skipped"
|
|
717
651
|
}
|
|
718
652
|
|
|
719
653
|
# ═══════════════════════════════════
|
|
720
|
-
# [
|
|
654
|
+
# [2/2] Register MCP with AI apps
|
|
721
655
|
# ═══════════════════════════════════
|
|
722
|
-
Write-Step "
|
|
656
|
+
Write-Step "2/2" "Register MCP with AI apps"
|
|
723
657
|
Write-Host " Automatic registration: Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity"
|
|
724
658
|
|
|
725
659
|
$detectedNames = @()
|
|
@@ -833,7 +767,12 @@ else {
|
|
|
833
767
|
}
|
|
834
768
|
|
|
835
769
|
Write-Host ""
|
|
836
|
-
$
|
|
770
|
+
if ($env:CI -eq 'true') {
|
|
771
|
+
Write-Host " Select apps to register (comma-separated, 'a' for all, 'n' to skip): a"
|
|
772
|
+
$selection = 'a'
|
|
773
|
+
} else {
|
|
774
|
+
$selection = Read-Host " Select apps to register (comma-separated, 'a' for all, 'n' to skip)"
|
|
775
|
+
}
|
|
837
776
|
if ([string]::IsNullOrWhiteSpace($selection)) { $selection = "n" }
|
|
838
777
|
|
|
839
778
|
$selectedIndices = @()
|
|
@@ -866,7 +805,8 @@ else {
|
|
|
866
805
|
elseif ($claudeCodeCliCommand) {
|
|
867
806
|
& $claudeCodeCliCommand mcp add weppy-roblox-mcp -- npx -y "@weppy/roblox-mcp"
|
|
868
807
|
if ($LASTEXITCODE -ne 0) {
|
|
869
|
-
|
|
808
|
+
# CLI 실패 시 (Windows에서 -- 파싱 문제 등) JSON config에 직접 쓰기로 폴백
|
|
809
|
+
Add-McpToConfig $claudeGlobalConfig
|
|
870
810
|
}
|
|
871
811
|
Write-Ok "Registered: $appName"
|
|
872
812
|
}
|
package/install.sh
CHANGED
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
# Usage:
|
|
6
6
|
# curl -fsSL https://raw.githubusercontent.com/hope1026/weppy-roblox-mcp/main/install.sh | bash
|
|
7
7
|
#
|
|
8
|
-
# Interactive
|
|
9
|
-
# [1/
|
|
10
|
-
# [2/
|
|
11
|
-
# [3/3] Register MCP with AI apps (user selection)
|
|
8
|
+
# Interactive 2 steps:
|
|
9
|
+
# [1/2] Setup — install Roblox Studio Plugin via npx
|
|
10
|
+
# [2/2] Register MCP with AI apps (user selection)
|
|
12
11
|
#
|
|
13
12
|
|
|
14
13
|
set -euo pipefail
|
|
@@ -74,6 +73,10 @@ trap 'handle_install_error "${LINENO}" "$BASH_COMMAND"' ERR
|
|
|
74
73
|
confirm() {
|
|
75
74
|
local prompt="$1"
|
|
76
75
|
local reply
|
|
76
|
+
if [ "${CI:-}" = "true" ]; then
|
|
77
|
+
printf "%s (Y/n): Y\n" "$prompt"
|
|
78
|
+
return 0
|
|
79
|
+
fi
|
|
77
80
|
printf "%s (Y/n): " "$prompt"
|
|
78
81
|
read -r reply </dev/tty
|
|
79
82
|
reply="${reply:-Y}"
|
|
@@ -610,16 +613,6 @@ resolve_optional_cli_command() {
|
|
|
610
613
|
return 1
|
|
611
614
|
}
|
|
612
615
|
|
|
613
|
-
is_lfs_pointer() {
|
|
614
|
-
local file_path="$1"
|
|
615
|
-
|
|
616
|
-
if [ ! -f "$file_path" ]; then
|
|
617
|
-
return 1
|
|
618
|
-
fi
|
|
619
|
-
|
|
620
|
-
grep -q "git-lfs.github.com/spec/v1" "$file_path"
|
|
621
|
-
}
|
|
622
|
-
|
|
623
616
|
# ── Header ──
|
|
624
617
|
# shellcheck disable=SC2059
|
|
625
618
|
printf "\n${BOLD}WROX Installer${NC}\n"
|
|
@@ -643,67 +636,24 @@ fi
|
|
|
643
636
|
success "Node.js $(node -v) detected"
|
|
644
637
|
|
|
645
638
|
# ═══════════════════════════════════
|
|
646
|
-
# [1/
|
|
647
|
-
# ═══════════════════════════════════
|
|
648
|
-
step "1/3" "Install @weppy/roblox-mcp via npm"
|
|
649
|
-
|
|
650
|
-
if confirm " Run npm install -g @weppy/roblox-mcp?"; then
|
|
651
|
-
if npm install -g @weppy/roblox-mcp; then
|
|
652
|
-
success "Installed @weppy/roblox-mcp"
|
|
653
|
-
else
|
|
654
|
-
fail "npm install failed"
|
|
655
|
-
exit 1
|
|
656
|
-
fi
|
|
657
|
-
else
|
|
658
|
-
warn "MCP server install skipped"
|
|
659
|
-
fi
|
|
660
|
-
|
|
661
|
-
# ═══════════════════════════════════
|
|
662
|
-
# [2/3] Roblox Studio Plugin install
|
|
639
|
+
# [1/2] Setup — Roblox Studio Plugin
|
|
663
640
|
# ═══════════════════════════════════
|
|
664
|
-
step "2
|
|
665
|
-
|
|
666
|
-
PLUGINS_DIR="$HOME/Documents/Roblox/Plugins"
|
|
667
|
-
PLUGIN_NAME="WeppyRobloxMCP.rbxm"
|
|
668
|
-
|
|
669
|
-
# Search for .rbxm in npm global prefix
|
|
670
|
-
NPM_PREFIX=$(npm prefix -g 2>/dev/null)
|
|
671
|
-
BUNDLED_PLUGIN=""
|
|
672
|
-
|
|
673
|
-
# Search for .rbxm in npm global path
|
|
674
|
-
for search_dir in \
|
|
675
|
-
"${NPM_PREFIX}/lib/node_modules/@weppy/roblox-mcp/plugins/weppy-roblox-mcp/roblox-plugin" \
|
|
676
|
-
"${NPM_PREFIX}/lib/node_modules/@weppy/roblox-mcp/roblox-plugin"; do
|
|
677
|
-
if [ -f "${search_dir}/${PLUGIN_NAME}" ]; then
|
|
678
|
-
BUNDLED_PLUGIN="${search_dir}/${PLUGIN_NAME}"
|
|
679
|
-
break
|
|
680
|
-
fi
|
|
681
|
-
done
|
|
682
|
-
|
|
683
|
-
if [ -n "$BUNDLED_PLUGIN" ]; then
|
|
684
|
-
if is_lfs_pointer "$BUNDLED_PLUGIN"; then
|
|
685
|
-
fail "Bundled plugin payload is invalid (Git LFS pointer detected)"
|
|
686
|
-
info "Install the plugin from the GitHub release ZIP instead"
|
|
687
|
-
exit 1
|
|
688
|
-
fi
|
|
641
|
+
step "1/2" "Setup Roblox Studio Plugin"
|
|
689
642
|
|
|
690
|
-
|
|
691
|
-
if
|
|
692
|
-
|
|
693
|
-
cp "$BUNDLED_PLUGIN" "$PLUGINS_DIR/$PLUGIN_NAME"
|
|
694
|
-
success "Plugin installed → $PLUGINS_DIR/$PLUGIN_NAME"
|
|
643
|
+
if confirm " Run npx -y @weppy/roblox-mcp --setup?"; then
|
|
644
|
+
if npx -y @weppy/roblox-mcp --setup; then
|
|
645
|
+
success "Setup complete"
|
|
695
646
|
else
|
|
696
|
-
warn "
|
|
647
|
+
warn "Setup encountered a warning (non-blocking)"
|
|
697
648
|
fi
|
|
698
649
|
else
|
|
699
|
-
warn "
|
|
700
|
-
info "Will be installed automatically on first MCP server run"
|
|
650
|
+
warn "Setup skipped"
|
|
701
651
|
fi
|
|
702
652
|
|
|
703
653
|
# ═══════════════════════════════════
|
|
704
|
-
# [
|
|
654
|
+
# [2/2] Register MCP with AI apps
|
|
705
655
|
# ═══════════════════════════════════
|
|
706
|
-
step "
|
|
656
|
+
step "2/2" "Register MCP with AI apps"
|
|
707
657
|
printf " Automatic registration: Claude Code, Claude Desktop, Cursor, Codex CLI/App, Gemini CLI, Antigravity\n"
|
|
708
658
|
|
|
709
659
|
MCP_COMMAND='npx -y @weppy/roblox-mcp'
|
|
@@ -811,7 +761,12 @@ else
|
|
|
811
761
|
# shellcheck disable=SC2059
|
|
812
762
|
printf "\n Select apps to register ${DIM}(comma-separated, 'a' for all, 'n' to skip)${NC}\n"
|
|
813
763
|
printf " → "
|
|
814
|
-
|
|
764
|
+
if [ "${CI:-}" = "true" ]; then
|
|
765
|
+
selection="a"
|
|
766
|
+
printf "a\n"
|
|
767
|
+
else
|
|
768
|
+
read -r selection </dev/tty
|
|
769
|
+
fi
|
|
815
770
|
selection="${selection:-n}"
|
|
816
771
|
|
|
817
772
|
# Parse selection
|
package/llms.txt
CHANGED
|
@@ -55,7 +55,7 @@ Manual alternative:
|
|
|
55
55
|
- WROX Dashboard guide: https://github.com/hope1026/weppy-roblox-mcp/blob/main/docs/en/dashboard/overview.md
|
|
56
56
|
- Troubleshooting: https://github.com/hope1026/weppy-roblox-mcp/blob/main/docs/troubleshooting.md
|
|
57
57
|
- Compatibility: https://github.com/hope1026/weppy-roblox-mcp/blob/main/docs/compatibility.md
|
|
58
|
-
- Pro upgrade: https://
|
|
58
|
+
- Pro upgrade: https://weppyai.com/en/plans
|
|
59
59
|
|
|
60
60
|
## Requirements
|
|
61
61
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weppy/roblox-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.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-OH9mpHwW.js";import{I as V}from"./InfoLabel-CLvjiyTG.js";import{D as F,P as G}from"./PropertyDiff-BnOZxkTS.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-BhDELp5r.js";import{I as V}from"./InfoLabel-CGOLGj5z.js";import{D as F,P as G}from"./PropertyDiff-DnLJY3ZB.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 D,D as O,u as F,j as e,T as I,c as V,i as U}from"./index-OH9mpHwW.js";import{C as G}from"./ConfirmModal-Dtak3Vnq.js";import{u as H,T as Z,D as W,a as q}from"./TierComparison-BA_L4c9p.js";import{t as d}from"./TierPromo.module-CAoUYgIx.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),[g,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 D.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,g)},[x,l,g]),_=i.useCallback(async()=>{await D.post("/api/dashboard/changelog/clear"),p([]),a(0),f(!1)},[]);return i.useEffect(()=>{x(l,g)},[x,l,g]),i.useEffect(()=>{const h=new O;b.current=h,h.connect();const o=h.on("command",()=>{x(l,g)});return()=>{o(),h.disconnect(),b.current=null}},[x,l,g]),{entries:t,total:s,hasMore:u,loading:r,offset:l,statusFilter:g,setOffset:C,setStatusFilter:j,refresh:y,clear:_}}const K="_card_1n89u_2",Q="_header_1n89u_17",X="_statusBadge_1n89u_24",Y="_statusDot_1n89u_35",ee="_active_1n89u_41",se="_completed_1n89u_50",te="_timeRange_1n89u_58",ae="_summaryList_1n89u_65",ne="_summaryItem_1n89u_71",oe="_summaryIcon_1n89u_80",ce="_summaryText_1n89u_86",ie="_progressBar_1n89u_91",re="_progressFill_1n89u_99",le="_emptySummary_1n89u_112",de="_contextBlock_1n89u_120",ge="_contextLabel_1n89u_129",me="_contextValue_1n89u_137",n={card:K,header:Q,statusBadge:X,statusDot:Y,active:ee,completed:se,timeRange:te,summaryList:ae,summaryItem:ne,summaryIcon:oe,summaryText:ce,progressBar:ie,progressFill:re,emptySummary:le,contextBlock:de,contextLabel:ge,contextValue:me};function E(t){if(!t)return"--:--";const p=new Date(t);return`${String(p.getHours()).padStart(2,"0")}:${String(p.getMinutes()).padStart(2,"0")}`}function he({entry:t,onClick:p}){var S,N,k,B,L,w,A,M,R,P;const{t:s}=F(),a=t.changeSummary,u=t.status==="active",f=t.isBootstrapOnly===!0,r=[],v=a.scriptsModified+a.scriptsCreated;if(v>0){const m=[];a.scriptsModified>0&&m.push(`${a.scriptsModified} ${s("changelog.card.modified","modified")}`),a.scriptsCreated>0&&m.push(`${a.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${v} ${s("changelog.card.scripts","scripts")} ${m.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 m=[];a.instancesCreated>0&&m.push(`${a.instancesCreated} ${s("changelog.card.created","created")}`),a.instancesDeleted>0&&m.push(`${a.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),a.instancesMoved>0&&m.push(`${a.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${l} ${s("changelog.card.instances","instances")} ${m.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=E(t.startTime),g=u?s("changelog.card.inProgress","in progress"):t.endTime?E(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=(P=(R=t.verificationSummary)==null?void 0:R.label)==null?void 0:P.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,"~",g]})]}),e.jsx("div",{className:n.summaryList,children:r.length>0?r.map((m,T)=>e.jsxs("div",{className:n.summaryItem,children:[e.jsx("span",{className:n.summaryIcon,children:m.icon}),e.jsx(I,{text:m.tooltip,children:e.jsx("span",{className:n.summaryText,children:m.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 pe="_page_1srvj_2",ue="_limitNotice_1srvj_9",fe="_limitNoticeTitle_1srvj_18",xe="_limitNoticeText_1srvj_25",_e="_headerRow_1srvj_31",ve="_header_1srvj_31",je="_clearButton_1srvj_48",be="_headerSub_1srvj_57",ye="_filterTabs_1srvj_67",Ne="_filterTab_1srvj_67",Ce="_filterTabActive_1srvj_90",Se="_list_1srvj_96",Te="_empty_1srvj_103",$e="_loading_1srvj_112",Ie="_pagination_1srvj_121",ke="_pageInfo_1srvj_129",Be="_btn_1srvj_135",c={page:pe,limitNotice:ue,limitNoticeTitle:fe,limitNoticeText:xe,headerRow:_e,header:ve,clearButton:je,headerSub:be,filterTabs:ye,filterTab:Ne,filterTabActive:Ce,list:Se,empty:Te,loading:$e,pagination:Ie,pageInfo:ke,btn:Be},$=10,Le=[{key:"all",label:"changelog.filter.all"},{key:"active",label:"changelog.filter.active"},{key:"completed",label:"changelog.filter.completed"}];function Pe(){const{t}=F(),p=V(),s=J(),a=H(),{show:u}=U(),[f,r]=i.useState(!1),[v,l]=i.useState(!1),[C,g]=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:Le.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(he,{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:d.progressPromoWrap,children:[e.jsxs("div",{className:d.progressPromo,children:[e.jsxs("div",{className:d.progressMain,children:[e.jsxs("div",{className:d.progressLabel,children:[e.jsx("span",{children:t("changelog.basic.metricLabel","Visible Changelog / Total")}),e.jsxs("span",{children:[y," / ",_]})]}),e.jsx("div",{className:d.progressBar,children:e.jsx("div",{className:d.progressFill,style:{width:`${_>0?Math.min(y/_*100,100):0}%`}})}),e.jsxs("div",{className:d.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:d.progressText,children:t("tier.banner.save","Save AI tokens with Pro!")}),e.jsxs("div",{className:d.actions,children:[e.jsx("button",{className:`${d.btn} ${d.btnOutline}`,onClick:()=>g(!0),children:t("tier.compare","Basic vs Pro")}),e.jsx("a",{className:`${d.btn} ${d.btnPrimary}`,href:Z.changelog,target:"_blank",rel:"noreferrer",children:t("tier.upgrade","Upgrade to Pro")})]})]}),e.jsx(W,{variant:"centered"})]})]}),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:()=>g(!1)})]})}export{Pe as Component};
|
|
1
|
+
import{r as i,a as D,D as O,u as F,j as e,T as I,c as V,i as U}from"./index-BhDELp5r.js";import{C as G}from"./ConfirmModal-BHlbjwL7.js";import{u as H,T as Z,D as W,a as q}from"./TierComparison-7eRDwSAZ.js";import{t as d}from"./TierPromo.module-CAoUYgIx.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),[g,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 D.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,g)},[x,l,g]),_=i.useCallback(async()=>{await D.post("/api/dashboard/changelog/clear"),p([]),a(0),f(!1)},[]);return i.useEffect(()=>{x(l,g)},[x,l,g]),i.useEffect(()=>{const h=new O;b.current=h,h.connect();const o=h.on("command",()=>{x(l,g)});return()=>{o(),h.disconnect(),b.current=null}},[x,l,g]),{entries:t,total:s,hasMore:u,loading:r,offset:l,statusFilter:g,setOffset:C,setStatusFilter:j,refresh:y,clear:_}}const K="_card_1n89u_2",Q="_header_1n89u_17",X="_statusBadge_1n89u_24",Y="_statusDot_1n89u_35",ee="_active_1n89u_41",se="_completed_1n89u_50",te="_timeRange_1n89u_58",ae="_summaryList_1n89u_65",ne="_summaryItem_1n89u_71",oe="_summaryIcon_1n89u_80",ce="_summaryText_1n89u_86",ie="_progressBar_1n89u_91",re="_progressFill_1n89u_99",le="_emptySummary_1n89u_112",de="_contextBlock_1n89u_120",ge="_contextLabel_1n89u_129",me="_contextValue_1n89u_137",n={card:K,header:Q,statusBadge:X,statusDot:Y,active:ee,completed:se,timeRange:te,summaryList:ae,summaryItem:ne,summaryIcon:oe,summaryText:ce,progressBar:ie,progressFill:re,emptySummary:le,contextBlock:de,contextLabel:ge,contextValue:me};function E(t){if(!t)return"--:--";const p=new Date(t);return`${String(p.getHours()).padStart(2,"0")}:${String(p.getMinutes()).padStart(2,"0")}`}function he({entry:t,onClick:p}){var S,N,k,B,L,w,A,M,R,P;const{t:s}=F(),a=t.changeSummary,u=t.status==="active",f=t.isBootstrapOnly===!0,r=[],v=a.scriptsModified+a.scriptsCreated;if(v>0){const m=[];a.scriptsModified>0&&m.push(`${a.scriptsModified} ${s("changelog.card.modified","modified")}`),a.scriptsCreated>0&&m.push(`${a.scriptsCreated} ${s("changelog.card.created","created")}`);const T=`${v} ${s("changelog.card.scripts","scripts")} ${m.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 m=[];a.instancesCreated>0&&m.push(`${a.instancesCreated} ${s("changelog.card.created","created")}`),a.instancesDeleted>0&&m.push(`${a.instancesDeleted} ${s("changelog.card.deleted","deleted")}`),a.instancesMoved>0&&m.push(`${a.instancesMoved} ${s("changelog.card.moved","moved")}`);const T=`${l} ${s("changelog.card.instances","instances")} ${m.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=E(t.startTime),g=u?s("changelog.card.inProgress","in progress"):t.endTime?E(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=(P=(R=t.verificationSummary)==null?void 0:R.label)==null?void 0:P.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,"~",g]})]}),e.jsx("div",{className:n.summaryList,children:r.length>0?r.map((m,T)=>e.jsxs("div",{className:n.summaryItem,children:[e.jsx("span",{className:n.summaryIcon,children:m.icon}),e.jsx(I,{text:m.tooltip,children:e.jsx("span",{className:n.summaryText,children:m.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 pe="_page_1srvj_2",ue="_limitNotice_1srvj_9",fe="_limitNoticeTitle_1srvj_18",xe="_limitNoticeText_1srvj_25",_e="_headerRow_1srvj_31",ve="_header_1srvj_31",je="_clearButton_1srvj_48",be="_headerSub_1srvj_57",ye="_filterTabs_1srvj_67",Ne="_filterTab_1srvj_67",Ce="_filterTabActive_1srvj_90",Se="_list_1srvj_96",Te="_empty_1srvj_103",$e="_loading_1srvj_112",Ie="_pagination_1srvj_121",ke="_pageInfo_1srvj_129",Be="_btn_1srvj_135",c={page:pe,limitNotice:ue,limitNoticeTitle:fe,limitNoticeText:xe,headerRow:_e,header:ve,clearButton:je,headerSub:be,filterTabs:ye,filterTab:Ne,filterTabActive:Ce,list:Se,empty:Te,loading:$e,pagination:Ie,pageInfo:ke,btn:Be},$=10,Le=[{key:"all",label:"changelog.filter.all"},{key:"active",label:"changelog.filter.active"},{key:"completed",label:"changelog.filter.completed"}];function Pe(){const{t}=F(),p=V(),s=J(),a=H(),{show:u}=U(),[f,r]=i.useState(!1),[v,l]=i.useState(!1),[C,g]=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:Le.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(he,{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:d.progressPromoWrap,children:[e.jsxs("div",{className:d.progressPromo,children:[e.jsxs("div",{className:d.progressMain,children:[e.jsxs("div",{className:d.progressLabel,children:[e.jsx("span",{children:t("changelog.basic.metricLabel","Visible Changelog / Total")}),e.jsxs("span",{children:[y," / ",_]})]}),e.jsx("div",{className:d.progressBar,children:e.jsx("div",{className:d.progressFill,style:{width:`${_>0?Math.min(y/_*100,100):0}%`}})}),e.jsxs("div",{className:d.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:d.progressText,children:t("tier.banner.save","Save AI tokens with Pro!")}),e.jsxs("div",{className:d.actions,children:[e.jsx("button",{className:`${d.btn} ${d.btnOutline}`,onClick:()=>g(!0),children:t("tier.compare","Basic vs Pro")}),e.jsx("a",{className:`${d.btn} ${d.btnPrimary}`,href:Z.changelog,target:"_blank",rel:"noreferrer",children:t("tier.upgrade","Upgrade to Pro")})]})]}),e.jsx(W,{variant:"centered"})]})]}),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:()=>g(!1)})]})}export{Pe as Component};
|