Add execution incidents, action bursts and shared Flash history. Expose verification and Explorer settings with streamed check results. Support graceful cancellation, recording recovery and bundled UI resources. Add CI quality checks and clean up comments and documentation.
194 lines
7.3 KiB
Python
194 lines
7.3 KiB
Python
# 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.
|
|
|
|
"""Interactive setup wizard for first-time ARTEMIS onboarding (artemis init)."""
|
|
|
|
import shutil
|
|
import subprocess
|
|
|
|
from rich.console import Console
|
|
from rich.panel import Panel
|
|
from rich.prompt import Prompt
|
|
|
|
from artemis.config.paths import get_env_file
|
|
|
|
|
|
def init_command() -> None:
|
|
"""Interactive quickstart wizard to configure API keys and connect your device."""
|
|
console = Console()
|
|
console.print()
|
|
console.print(
|
|
Panel(
|
|
"[bold cyan]☕ Welcome to Artemis Mobile Testing Framework[/bold cyan]\n"
|
|
"[dim]Let's get you set up in 10 seconds![/dim]",
|
|
expand=False,
|
|
)
|
|
)
|
|
|
|
# 1. Select Provider
|
|
console.print("\n[bold]Step 1: Choose Primary LLM Provider[/bold]")
|
|
console.print(" [1] Google Gemini (Recommended - Default)")
|
|
console.print(" [2] OpenAI (GPT-4o)")
|
|
console.print(" [3] Anthropic (Claude 3.5 Sonnet)")
|
|
console.print(" [4] OpenRouter")
|
|
|
|
choice = Prompt.ask("Select provider", choices=["1", "2", "3", "4"], default="1")
|
|
provider_map = {
|
|
"1": ("GEMINI_API_KEY", "Google Gemini"),
|
|
"2": ("OPENAI_API_KEY", "OpenAI"),
|
|
"3": ("ANTHROPIC_API_KEY", "Anthropic"),
|
|
"4": ("OPEN_ROUTER_API_KEY", "OpenRouter"),
|
|
}
|
|
env_key, provider_name = provider_map[choice]
|
|
|
|
# 2. Enter API Key
|
|
console.print(f"\n[bold]Step 2: Enter your {provider_name} API Key[/bold]")
|
|
api_key = Prompt.ask(f"Enter {env_key}", password=True)
|
|
while not api_key.strip():
|
|
console.print("[bold red]API Key cannot be empty.[/bold red]")
|
|
api_key = Prompt.ask(f"Enter {env_key}", password=True)
|
|
|
|
# 3. Scan for Android Devices
|
|
console.print("\n[bold]Step 3: Detecting Android Devices / Emulators...[/bold]")
|
|
detected_devices = []
|
|
adb_path = shutil.which("adb")
|
|
if adb_path:
|
|
try:
|
|
res = subprocess.run(
|
|
[adb_path, "devices", "-l"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5,
|
|
)
|
|
lines = [line_str.strip() for line_str in res.stdout.splitlines() if line_str.strip()]
|
|
for line in lines[1:]:
|
|
parts = line.split()
|
|
if len(parts) >= 2 and parts[1] == "device":
|
|
serial = parts[0]
|
|
extra = " ".join(parts[2:])
|
|
detected_devices.append((serial, extra))
|
|
except (OSError, subprocess.SubprocessError):
|
|
# adb probe failed or timed out; continue setup with no devices.
|
|
pass
|
|
|
|
selected_serial = ""
|
|
if detected_devices:
|
|
console.print(
|
|
f"[bold green]✔ Found {len(detected_devices)} connected device(s):[/bold green]"
|
|
)
|
|
for idx, (serial, extra) in enumerate(detected_devices, 1):
|
|
console.print(f" [{idx}] {serial} ({extra})")
|
|
if len(detected_devices) == 1:
|
|
selected_serial = detected_devices[0][0]
|
|
console.print(f"[dim]Auto-selected device: {selected_serial}[/dim]")
|
|
else:
|
|
dev_choice = Prompt.ask(
|
|
"Select device index",
|
|
choices=[str(i) for i in range(1, len(detected_devices) + 1)],
|
|
default="1",
|
|
)
|
|
selected_serial = detected_devices[int(dev_choice) - 1][0]
|
|
else:
|
|
console.print(
|
|
"[bold yellow]⚠ No connected device detected right now.[/bold yellow]\n"
|
|
"[dim]Artemis will auto-detect your device when you connect it later.[/dim]"
|
|
)
|
|
|
|
# 4. Generate .env File
|
|
env_content = [
|
|
"# ==============================================================================",
|
|
"# ☕ ARTEMIS Environment Configuration (Generated by 'artemis init')",
|
|
"# ==============================================================================",
|
|
f"{env_key}={api_key.strip()}",
|
|
"",
|
|
"# Android Device Configuration",
|
|
"ADB_HOST=127.0.0.1",
|
|
"ADB_PORT=5037",
|
|
]
|
|
if selected_serial:
|
|
env_content.append(f"ADB_DEVICE_SERIAL={selected_serial}")
|
|
else:
|
|
env_content.append("# ADB_DEVICE_SERIAL=emulator-5554")
|
|
|
|
env_content.extend(
|
|
[
|
|
"",
|
|
"# Execution Defaults",
|
|
"ARTEMIS_DEFAULT_PROFILE=pro",
|
|
"ARTEMIS_DEFAULT_MODEL=gemini-2.5-flash",
|
|
"ARTEMIS_TRACES_DIR=./traces",
|
|
"",
|
|
]
|
|
)
|
|
|
|
env_path = get_env_file()
|
|
env_path.parent.mkdir(parents=True, exist_ok=True)
|
|
env_path.write_text("\n".join(env_content), encoding="utf-8")
|
|
|
|
# 5. Configure MCP for AI IDEs
|
|
console.print("\n[bold]Step 5: Connect Artemis to your AI IDE (MCP)[/bold]")
|
|
console.print(" [1] Antigravity / Jetski (Recommended - Default)")
|
|
console.print(" [2] Cursor")
|
|
console.print(" [3] Claude Desktop / Claude Code")
|
|
console.print(" [4] Windsurf")
|
|
console.print(" [5] VS Code / Cline / Roo Code")
|
|
console.print(" [6] Codex")
|
|
console.print(" [7] All supported IDEs")
|
|
console.print(" [8] Skip for now")
|
|
mcp_choice = Prompt.ask(
|
|
"Select IDE for MCP auto-install",
|
|
choices=["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
default="1",
|
|
)
|
|
if mcp_choice != "8":
|
|
target_map = {
|
|
"1": "antigravity",
|
|
"2": "cursor",
|
|
"3": "claude",
|
|
"4": "windsurf",
|
|
"5": "vscode",
|
|
"6": "codex",
|
|
"7": "all",
|
|
}
|
|
target = target_map.get(mcp_choice, "antigravity")
|
|
try:
|
|
from artemis.interfaces.cli.commands.mcp import install_mcp_config
|
|
from mcp_server.utils import env_utils
|
|
|
|
proj_root = env_utils.get_project_root()
|
|
py_exe = env_utils.resolve_python_executable(proj_root)
|
|
installed_paths = install_mcp_config(target, py_exe, proj_root)
|
|
console.print(
|
|
f"[bold green]✔ Configured Artemis MCP in {len(installed_paths)} IDE location(s).[/bold green]"
|
|
)
|
|
except Exception as e:
|
|
console.print(f"[yellow]Could not auto-install MCP config: {e}[/yellow]")
|
|
|
|
console.print()
|
|
console.print(
|
|
Panel(
|
|
f"[bold green]🎉 Setup completed successfully![/bold green]\n\n"
|
|
f"Configured [bold cyan]{provider_name}[/bold cyan] in [dim]{env_path}[/dim]\n\n"
|
|
"Try running your first task:\n"
|
|
' [bold cyan]uv run artemis run "Open YouTube and search for Lo-Fi Hip Hop"[/bold cyan]\n\n'
|
|
"Or connect/update your AI IDE anytime with:\n"
|
|
" [bold cyan]uv run artemis mcp --install all[/bold cyan]\n\n"
|
|
"Or run health diagnostics anytime with:\n"
|
|
" [bold cyan]uv run artemis doctor[/bold cyan]",
|
|
title="☕ Ready to Go!",
|
|
expand=False,
|
|
)
|
|
)
|
|
console.print()
|