Localize the web console and persist custom model and capability settings. Use OpenAI Responses exclusively and move runtime limits into environment configuration. Bootstrap uv and the virtual environment on Windows, support optional China mirrors, and package source distributions without environments, build output, or credentials. Update regression tests and repository quality checks for the new behavior.
507 lines
22 KiB
PowerShell
507 lines
22 KiB
PowerShell
# Copyright 2026 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[int]$Port = 8000,
|
|
[switch]$NoOpen = $false,
|
|
[switch]$SetupOnly = $false,
|
|
[ValidateSet('Official', 'China')][string]$Mirror
|
|
)
|
|
|
|
$ErrorActionPreference = "Continue"
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
|
|
# Ensure modern TLS protocols are enabled for downloads (GitHub releases, nodejs.org, Google repositories)
|
|
try {
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
|
|
} catch {}
|
|
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
$RootDir = Split-Path -Parent $ScriptDir
|
|
Set-Location $RootDir
|
|
|
|
. (Join-Path $ScriptDir 'download_config.ps1')
|
|
try {
|
|
Initialize-ArtemisDownloads -ProjectRoot $RootDir -Mode $Mirror
|
|
} catch {
|
|
Write-Host " [ERROR] Invalid download settings: $_" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "======================================================" -ForegroundColor Cyan
|
|
Write-Host " Artemis Autonomous Mobile Agent UI " -ForegroundColor Cyan
|
|
Write-Host "======================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
function Update-EnvironmentPath {
|
|
$standardDirs = @(
|
|
"$env:LOCALAPPDATA\Microsoft\WinGet\Links",
|
|
"$env:LOCALAPPDATA\Programs\node",
|
|
"$env:USERPROFILE\.local\share\node",
|
|
"$env:LOCALAPPDATA\Programs\scrcpy",
|
|
"$env:USERPROFILE\.local\share\scrcpy",
|
|
"$env:LOCALAPPDATA\Programs\platform-tools",
|
|
"$env:USERPROFILE\.local\share\platform-tools",
|
|
"$env:LOCALAPPDATA\Programs\uv",
|
|
"$env:LOCALAPPDATA\uv",
|
|
"$env:APPDATA\uv",
|
|
"$env:USERPROFILE\.cargo\bin",
|
|
"$env:USERPROFILE\.local\bin",
|
|
"$env:USERPROFILE\scoop\shims",
|
|
"C:\ProgramData\chocolatey\bin",
|
|
"$env:LOCALAPPDATA\Android\Sdk\platform-tools",
|
|
"$env:LOCALAPPDATA\Android\android-sdk\platform-tools",
|
|
"$env:ProgramFiles\Android\platform-tools",
|
|
"${env:ProgramFiles(x86)}\Android\android-sdk\platform-tools",
|
|
"$env:ProgramFiles\nodejs",
|
|
"${env:ProgramFiles(x86)}\nodejs",
|
|
"$env:APPDATA\npm"
|
|
)
|
|
if ($env:CARGO_HOME) { $standardDirs = @("$env:CARGO_HOME\bin") + $standardDirs }
|
|
if ($env:ANDROID_HOME) { $standardDirs += "$env:ANDROID_HOME\platform-tools" }
|
|
if ($env:ANDROID_SDK_ROOT) { $standardDirs += "$env:ANDROID_SDK_ROOT\platform-tools" }
|
|
if ($env:NVM_SYMLINK) { $standardDirs = @($env:NVM_SYMLINK) + $standardDirs }
|
|
if ($env:NVM_HOME) { $standardDirs = @($env:NVM_HOME) + $standardDirs }
|
|
|
|
$regPath = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
|
|
$currentPaths = ($env:PATH -split ";") + ($regPath -split ";") + $standardDirs | Where-Object { [string]::IsNullOrWhiteSpace($_) -eq $false -and (Test-Path $_) } | Select-Object -Unique
|
|
$env:PATH = $currentPaths -join ";"
|
|
|
|
# Ensure user-space portable tools take absolute priority over system-level outdated versions
|
|
$portableNode = "$env:LOCALAPPDATA\Programs\node"
|
|
if (Test-Path "$portableNode\node.exe") {
|
|
$env:PATH = "$portableNode;$env:PATH"
|
|
}
|
|
$portableScrcpy = "$env:LOCALAPPDATA\Programs\scrcpy"
|
|
if (Test-Path "$portableScrcpy\scrcpy.exe") {
|
|
$env:PATH = "$portableScrcpy;$env:PATH"
|
|
}
|
|
$portablePt = "$env:LOCALAPPDATA\Programs\platform-tools"
|
|
if (Test-Path "$portablePt\adb.exe") {
|
|
$env:PATH = "$portablePt;$env:PATH"
|
|
}
|
|
}
|
|
|
|
function Start-LocalAdbServer {
|
|
if (Test-CommandExists "adb") {
|
|
try {
|
|
$origSocket = $env:ADB_SERVER_SOCKET
|
|
Remove-Item Env:\ADB_SERVER_SOCKET -ErrorAction SilentlyContinue
|
|
& adb start-server 2>$null | Out-Null
|
|
if ($origSocket) { $env:ADB_SERVER_SOCKET = $origSocket }
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
function Test-CommandExists {
|
|
param([string]$Command)
|
|
$res = Get-Command $Command -ErrorAction SilentlyContinue
|
|
return ($null -ne $res)
|
|
}
|
|
|
|
function Invoke-DownloadFile {
|
|
param(
|
|
[Parameter(Mandatory=$true)][string]$Uri,
|
|
[Parameter(Mandatory=$true)][string]$OutFile,
|
|
[int]$TimeoutSec = $ArtemisDownloads.timeout_seconds
|
|
)
|
|
if (Test-Path $OutFile) {
|
|
Remove-Item -Path $OutFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# 1. Try Windows built-in curl.exe first (available in Win 10 1803+ and Win 11)
|
|
if (Test-CommandExists "curl.exe") {
|
|
try {
|
|
& curl.exe -f -sSL --connect-timeout 5 --max-time $TimeoutSec "$Uri" -o "$OutFile" 2>$null
|
|
if ($LASTEXITCODE -eq 0 -and (Test-Path $OutFile) -and ((Get-Item $OutFile).Length -gt 0)) {
|
|
return $true
|
|
}
|
|
} catch {}
|
|
if (Test-Path $OutFile) {
|
|
Remove-Item -Path $OutFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
# 2. Fallback to Invoke-WebRequest (suppressing progress bar to eliminate PowerShell buffer hangs)
|
|
try {
|
|
$prevProgress = $ProgressPreference
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
Invoke-WebRequest -Uri $Uri -OutFile $OutFile -TimeoutSec $TimeoutSec -UseBasicParsing -ErrorAction Stop
|
|
$ProgressPreference = $prevProgress
|
|
if ((Test-Path $OutFile) -and ((Get-Item $OutFile).Length -gt 0)) {
|
|
return $true
|
|
}
|
|
} catch {
|
|
$ProgressPreference = $prevProgress
|
|
}
|
|
|
|
if (Test-Path $OutFile) {
|
|
Remove-Item -Path $OutFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Install-PortablePlatformTools {
|
|
$ptDir = "$env:LOCALAPPDATA\Programs\platform-tools"
|
|
if (Test-Path "$ptDir\adb.exe") {
|
|
$env:PATH = "$ptDir;$env:PATH"
|
|
return $true
|
|
}
|
|
Write-Host " [INFO] Installing Android platform-tools (adb) in user space..." -ForegroundColor Cyan
|
|
try {
|
|
$zipPath = "$env:TEMP\platform-tools-windows.zip"
|
|
if (Invoke-DownloadFile -Uri $ArtemisDownloads.adb_url -OutFile $zipPath) {
|
|
New-Item -ItemType Directory -Path "$env:LOCALAPPDATA\Programs" -Force | Out-Null
|
|
Expand-Archive -Path $zipPath -DestinationPath "$env:LOCALAPPDATA\Programs" -Force
|
|
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
if (Test-Path "$ptDir\adb.exe") {
|
|
$env:PATH = "$ptDir;$env:PATH"
|
|
Write-Host " [OK] adb installed in user space." -ForegroundColor Green
|
|
return $true
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Host " [WARN] Failed to install portable platform-tools: $_" -ForegroundColor DarkYellow
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Install-PortableScrcpy {
|
|
$scrcpyDir = "$env:LOCALAPPDATA\Programs\scrcpy"
|
|
if (Test-Path "$scrcpyDir\scrcpy.exe") {
|
|
$env:PATH = "$scrcpyDir;$env:PATH"
|
|
return $true
|
|
}
|
|
# Check if nested from an earlier run and heal
|
|
$nested = Get-ChildItem -Path $scrcpyDir -Directory -Filter "scrcpy*" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($nested -and (Test-Path "$($nested.FullName)\scrcpy.exe")) {
|
|
Copy-Item -Path "$($nested.FullName)\*" -Destination $scrcpyDir -Recurse -Force
|
|
Remove-Item -Path $nested.FullName -Recurse -Force -ErrorAction SilentlyContinue
|
|
if (Test-Path "$scrcpyDir\scrcpy.exe") {
|
|
$env:PATH = "$scrcpyDir;$env:PATH"
|
|
return $true
|
|
}
|
|
}
|
|
|
|
Write-Host " [INFO] Installing portable scrcpy in user space..." -ForegroundColor Cyan
|
|
if ($ArtemisDownloads.mode -eq 'China' -and $ArtemisDownloads.scrcpy_url.StartsWith('https://github.com/')) {
|
|
Write-Host ' [INFO] scrcpy uses GitHub. If unreachable, set overrides.scrcpy_url in config/downloads.json.' -ForegroundColor Yellow
|
|
}
|
|
try {
|
|
$zipPath = "$env:TEMP\scrcpy-win64.zip"
|
|
if (Invoke-DownloadFile -Uri $ArtemisDownloads.scrcpy_url -OutFile $zipPath) {
|
|
$extractDir = "$env:TEMP\scrcpy_extract"
|
|
if (Test-Path $extractDir) { Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue }
|
|
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
|
|
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
|
|
$extractedFolder = Get-ChildItem -Path $extractDir -Directory | Select-Object -First 1
|
|
if ($extractedFolder) {
|
|
if (-not (Test-Path $scrcpyDir)) {
|
|
New-Item -ItemType Directory -Path $scrcpyDir -Force | Out-Null
|
|
}
|
|
Copy-Item -Path "$($extractedFolder.FullName)\*" -Destination $scrcpyDir -Recurse -Force
|
|
}
|
|
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
if (Test-Path "$scrcpyDir\scrcpy.exe") {
|
|
$env:PATH = "$scrcpyDir;$env:PATH"
|
|
Write-Host " [OK] Portable scrcpy installed in user space." -ForegroundColor Green
|
|
return $true
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Host " [WARN] Failed to install portable scrcpy: $_" -ForegroundColor DarkYellow
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Test-NodeCompatible {
|
|
if (-not (Test-CommandExists "node") -or (-not (Test-CommandExists "npm") -and -not (Test-CommandExists "npm.cmd"))) { return $false }
|
|
try {
|
|
$verRaw = (& node -v 2>$null)
|
|
if (-not $verRaw) { return $false }
|
|
$verStr = $verRaw.ToString().Trim().TrimStart('v')
|
|
$parts = $verStr.Split('.')
|
|
if ($parts.Count -ge 2) {
|
|
$major = [int]$parts[0]
|
|
$minor = [int]$parts[1]
|
|
if ($major -ge 26) { return $true }
|
|
if ($major -eq 24 -and $minor -ge 15) { return $true }
|
|
if ($major -eq 22 -and $minor -ge 22) { return $true }
|
|
}
|
|
} catch {
|
|
return $false
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Install-PortableNode {
|
|
$nodeDir = "$env:LOCALAPPDATA\Programs\node"
|
|
if (Test-Path "$nodeDir\node.exe") {
|
|
$env:PATH = "$nodeDir;$env:PATH"
|
|
if (Test-NodeCompatible) {
|
|
return $true
|
|
}
|
|
}
|
|
# Check if nested from an earlier run and heal
|
|
$nested = Get-ChildItem -Path $nodeDir -Directory -Filter "node-*" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($nested -and (Test-Path "$($nested.FullName)\node.exe")) {
|
|
Copy-Item -Path "$($nested.FullName)\*" -Destination $nodeDir -Recurse -Force
|
|
Remove-Item -Path $nested.FullName -Recurse -Force -ErrorAction SilentlyContinue
|
|
if (Test-Path "$nodeDir\node.exe") {
|
|
$env:PATH = "$nodeDir;$env:PATH"
|
|
if (Test-NodeCompatible) {
|
|
return $true
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host " [INFO] Installing portable Node.js LTS (v22.23.2) in user space..." -ForegroundColor Cyan
|
|
try {
|
|
$nodeVer = "v22.23.2"
|
|
$arch = if ([System.Environment]::Is64BitOperatingSystem) {
|
|
if ($env:PROCESSOR_ARCHITECTURE -match "ARM64") { "arm64" } else { "x64" }
|
|
} else { "x64" }
|
|
$zipPath = "$env:TEMP\node-$nodeVer-win-$arch.zip"
|
|
$nodeBase = $ArtemisDownloads.node_mirror.TrimEnd('/')
|
|
if (Invoke-DownloadFile -Uri "$nodeBase/$nodeVer/node-$nodeVer-win-$arch.zip" -OutFile $zipPath) {
|
|
$extractDir = "$env:TEMP\node_extract"
|
|
if (Test-Path $extractDir) { Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue }
|
|
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
|
|
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
|
|
$extractedFolder = Get-ChildItem -Path $extractDir -Directory | Select-Object -First 1
|
|
if ($extractedFolder) {
|
|
if (-not (Test-Path $nodeDir)) {
|
|
New-Item -ItemType Directory -Path $nodeDir -Force | Out-Null
|
|
}
|
|
Copy-Item -Path "$($extractedFolder.FullName)\*" -Destination $nodeDir -Recurse -Force
|
|
}
|
|
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
if (Test-Path "$nodeDir\node.exe") {
|
|
$env:PATH = "$nodeDir;$env:PATH"
|
|
Write-Host " [OK] Portable Node.js $nodeVer installed in user space." -ForegroundColor Green
|
|
return $true
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Host " [WARN] Failed to install portable Node.js: $_" -ForegroundColor DarkYellow
|
|
}
|
|
return $false
|
|
}
|
|
|
|
# 1. Refresh PATH with standard toolchain paths
|
|
Update-EnvironmentPath
|
|
|
|
# 2. Prepare the project Python environment before optional device/UI setup.
|
|
. (Join-Path $ScriptDir 'bootstrap_python.ps1')
|
|
try {
|
|
$ArtemisPython = Initialize-ArtemisPython -ProjectRoot $RootDir
|
|
} catch {
|
|
Write-Host " [ERROR] $_" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $RootDir '.env'))) {
|
|
if (Test-Path -LiteralPath (Join-Path $RootDir '.env.example')) {
|
|
Copy-Item -LiteralPath (Join-Path $RootDir '.env.example') -Destination (Join-Path $RootDir '.env') -ErrorAction Stop
|
|
Write-Host ' [OK] Created .env from .env.example. Configure your model in the web UI.' -ForegroundColor Green
|
|
}
|
|
}
|
|
if ($SetupOnly) {
|
|
Write-Host ' [OK] Setup complete. Run start.bat to launch Artemis.' -ForegroundColor Green
|
|
exit 0
|
|
}
|
|
|
|
# 3. Check and try installing missing system toolchains (ADB, FFmpeg, scrcpy)
|
|
$missingCore = @()
|
|
if (-not (Test-CommandExists "adb")) { $missingCore += "adb" }
|
|
# imageio-ffmpeg ships a working executable in its wheel, including mirror installs.
|
|
if (-not (Test-CommandExists "ffmpeg")) {
|
|
& $ArtemisPython -c 'import imageio_ffmpeg; imageio_ffmpeg.get_ffmpeg_exe()' 2>$null | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { $missingCore += "ffmpeg" }
|
|
}
|
|
if (-not (Test-CommandExists "scrcpy")) { $missingCore += "scrcpy" }
|
|
|
|
if ($missingCore.Count -gt 0) {
|
|
$useWinGet = $false
|
|
if ($ArtemisDownloads.mode -ne 'China' -and (Test-CommandExists "winget")) {
|
|
if ([Console]::IsInputRedirected -eq $false) {
|
|
Write-Host " [INFO] Missing components detected: $($missingCore -join ', ')." -ForegroundColor Cyan
|
|
$ans = Read-Host " Install system packages via WinGet? [Y/n]"
|
|
if ($ans -eq "" -or $ans -match "^[Yy]") {
|
|
$useWinGet = $true
|
|
}
|
|
} else {
|
|
$useWinGet = $true
|
|
}
|
|
}
|
|
|
|
if ($useWinGet) {
|
|
Write-Host " [INFO] Auto-installing missing components ($($missingCore -join ', '))..." -ForegroundColor DarkYellow
|
|
if ($missingCore -contains "adb") {
|
|
winget install --id Google.PlatformTools -e --accept-source-agreements --accept-package-agreements --silent 2>$null | Out-Null
|
|
}
|
|
if ($missingCore -contains "ffmpeg") {
|
|
winget install --id Gyan.FFmpeg -e --accept-source-agreements --accept-package-agreements --silent 2>$null | Out-Null
|
|
}
|
|
if ($missingCore -contains "scrcpy") {
|
|
winget install --id Genymobile.scrcpy -e --accept-source-agreements --accept-package-agreements --silent 2>$null | Out-Null
|
|
}
|
|
Update-EnvironmentPath
|
|
}
|
|
|
|
# Zero-admin user-space fallback for adb and scrcpy if still missing
|
|
if (-not (Test-CommandExists "adb")) {
|
|
Install-PortablePlatformTools
|
|
}
|
|
if (-not (Test-CommandExists "scrcpy")) {
|
|
if (-not (Install-PortableScrcpy)) {
|
|
Write-Host ' [WARN] scrcpy download failed. Set overrides.scrcpy_url in config/downloads.json to a reachable release ZIP, then retry.' -ForegroundColor Yellow
|
|
}
|
|
}
|
|
}
|
|
|
|
# Ensure local ADB daemon is warm & listening so probes do not hit 'Connection refused'
|
|
Start-LocalAdbServer
|
|
|
|
# 6. Check and build Showcase UI if not already compiled
|
|
$ShowcaseIndex = "$RootDir\apps\showcase_ui\dist\frontend\browser\index.html"
|
|
$ShowcaseIndexAlt1 = "$RootDir\apps\showcase_ui\dist\browser\index.html"
|
|
$ShowcaseIndexAlt2 = "$RootDir\apps\showcase_ui\dist\index.html"
|
|
if ((-not (Test-Path $ShowcaseIndex)) -and (-not (Test-Path $ShowcaseIndexAlt1)) -and (-not (Test-Path $ShowcaseIndexAlt2))) {
|
|
if (-not (Test-NodeCompatible)) {
|
|
if (Test-CommandExists "node") {
|
|
$curVer = (& node -v 2>$null)
|
|
Write-Host " [INFO] Detected Node.js $curVer, but Angular CLI requires Node.js >= v22.22.0." -ForegroundColor Yellow
|
|
} else {
|
|
Write-Host " [INFO] Node.js/npm not found (required for Showcase UI)." -ForegroundColor Cyan
|
|
}
|
|
|
|
# 1. Try nvm if available on Windows
|
|
if ($ArtemisDownloads.mode -ne 'China' -and (Test-CommandExists "nvm")) {
|
|
Write-Host " [INFO] Installing Node.js 22 LTS via nvm..." -ForegroundColor Cyan
|
|
& nvm install 22.23.2 | Out-Null
|
|
& nvm use 22.23.2 | Out-Null
|
|
Update-EnvironmentPath
|
|
}
|
|
|
|
# 2. Try WinGet
|
|
if (-not (Test-NodeCompatible)) {
|
|
$useWinGetNode = $false
|
|
if ($ArtemisDownloads.mode -ne 'China' -and (Test-CommandExists "winget")) {
|
|
if ([Console]::IsInputRedirected -eq $false) {
|
|
Write-Host " [INFO] Node.js >= v22.22.0 required for Showcase UI." -ForegroundColor Cyan
|
|
$ans = Read-Host " Install/Upgrade Node.js via WinGet (may require Administrator)? [Y/n]"
|
|
if ($ans -eq "" -or $ans -match "^[Yy]") {
|
|
$useWinGetNode = $true
|
|
}
|
|
} else {
|
|
$useWinGetNode = $true
|
|
}
|
|
}
|
|
|
|
if ($useWinGetNode) {
|
|
Write-Host " [INFO] Installing/Upgrading Node.js LTS via WinGet..." -ForegroundColor Yellow
|
|
winget install --id OpenJS.NodeJS.LTS -e --accept-source-agreements --accept-package-agreements --silent 2>$null | Out-Null
|
|
Update-EnvironmentPath
|
|
}
|
|
}
|
|
|
|
# 3. Zero-admin user-space fallback for Node.js if still not compatible
|
|
if (-not (Test-NodeCompatible)) {
|
|
Install-PortableNode
|
|
}
|
|
}
|
|
|
|
if (Test-NodeCompatible) {
|
|
$nodeVer = (& node -v 2>$null)
|
|
Write-Host " [OK] Node.js $nodeVer is ready." -ForegroundColor Green
|
|
Write-Host " [INFO] Showcase UI build not found. Compiling Angular Showcase UI..." -ForegroundColor Yellow
|
|
Push-Location "$RootDir\apps\showcase_ui"
|
|
try {
|
|
$npmExec = if (Test-CommandExists "npm.cmd") { "npm.cmd" } else { "npm" }
|
|
Write-Host " [INFO] Installing frontend npm dependencies..." -ForegroundColor Cyan
|
|
& $npmExec ci --no-audit --no-fund --loglevel=error
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "npm ci failed (exit $LASTEXITCODE). Check the network and retry."
|
|
}
|
|
Write-Host " [INFO] Building Angular frontend application..." -ForegroundColor Cyan
|
|
& $npmExec run build
|
|
if ($LASTEXITCODE -ne 0) { throw "Frontend build failed (exit $LASTEXITCODE)." }
|
|
if (Test-Path $ShowcaseIndex) {
|
|
Write-Host " [OK] Showcase UI compiled successfully." -ForegroundColor Green
|
|
} elseif (Test-Path $ShowcaseIndexAlt1) {
|
|
Write-Host " [OK] Showcase UI compiled successfully." -ForegroundColor Green
|
|
} else {
|
|
throw 'Frontend build did not produce index.html.'
|
|
}
|
|
} catch {
|
|
Write-Host " [ERROR] Failed to build Showcase UI: $_" -ForegroundColor Red
|
|
exit 1
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
} else {
|
|
Write-Host " [ERROR] A compatible Node.js/npm could not be installed. Install Node.js LTS and retry." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# 7. Optionally configure MCP for detected AI IDEs
|
|
Write-Host ""
|
|
Write-Host " [INFO] Would you like to configure ARTEMIS MCP & testing rules for your AI IDEs?" -ForegroundColor Cyan
|
|
Write-Host " (Supported: Antigravity, Cursor, Claude Code/Desktop, Codex, OpenClaw, Windsurf)"
|
|
$installMcp = "Y"
|
|
if ([Console]::IsInputRedirected -eq $false) {
|
|
$response = Read-Host " Install MCP configuration & rules now? [Y/n]"
|
|
if ($response -ne "") {
|
|
$installMcp = $response
|
|
}
|
|
} else {
|
|
$installMcp = "N"
|
|
}
|
|
|
|
if ($installMcp -match "^[Yy]") {
|
|
Write-Host " Installing MCP server configuration & testing rules..." -ForegroundColor Cyan
|
|
& $ArtemisPython -m artemis mcp --install all
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host " [OK] MCP configuration and rules installed successfully." -ForegroundColor Green
|
|
Write-Host " [TIP] You can update or re-install anytime with: uv run artemis mcp --install all" -ForegroundColor Cyan
|
|
} else {
|
|
Write-Host " [WARN] MCP installation failed. Review the error above and retry with: uv run artemis mcp --install all" -ForegroundColor Yellow
|
|
}
|
|
} else {
|
|
Write-Host " [SKIP] You can install MCP anytime later with: uv run artemis mcp --install all" -ForegroundColor Yellow
|
|
}
|
|
Write-Host ""
|
|
|
|
# 8. Launch unified Showcase UI & open browser
|
|
# Ensure local ADB daemon is warm & listening
|
|
Start-LocalAdbServer
|
|
|
|
# Launch via `python -m artemis` (not the `artemis.exe` console-script shim) so the
|
|
# long-running server never locks .venv\Scripts\artemis.exe against `uv sync` reinstalls.
|
|
Write-Host " [INFO] Launching Artemis Showcase UI & Admin Console..." -ForegroundColor Green
|
|
if ($NoOpen) {
|
|
& $ArtemisPython -m artemis ui --port $Port --no-open
|
|
} else {
|
|
& $ArtemisPython -m artemis ui --port $Port --open
|
|
}
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
exit $LASTEXITCODE
|
|
}
|