android-midscene-automation 0.2.4 → 1.1.1
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/CHANGELOG.md +10 -0
- package/README.md +159 -29
- package/artemis-main/.dockerignore +15 -0
- package/artemis-main/.env.example +34 -0
- package/artemis-main/CONTRIBUTING.md +35 -0
- package/artemis-main/Dockerfile +68 -0
- package/artemis-main/LICENSE +202 -0
- package/artemis-main/Makefile +115 -0
- package/artemis-main/README.md +322 -0
- package/artemis-main/README_CN.md +320 -0
- package/artemis-main/apps/__init__.py +15 -0
- package/artemis-main/apps/admin_console/__init__.py +19 -0
- package/artemis-main/apps/admin_console/core/__init__.py +13 -0
- package/artemis-main/apps/admin_console/core/config.py +43 -0
- package/artemis-main/apps/admin_console/core/security.py +178 -0
- package/artemis-main/apps/admin_console/core/state.py +243 -0
- package/artemis-main/apps/admin_console/database/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/connection.py +60 -0
- package/artemis-main/apps/admin_console/database/repositories/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/repositories/session_repository.py +564 -0
- package/artemis-main/apps/admin_console/database/repositories/step_repository.py +512 -0
- package/artemis-main/apps/admin_console/database/repositories/trace_repository.py +133 -0
- package/artemis-main/apps/admin_console/index.html +3787 -0
- package/artemis-main/apps/admin_console/replay_manager.py +2585 -0
- package/artemis-main/apps/admin_console/routers/__init__.py +13 -0
- package/artemis-main/apps/admin_console/routers/media.py +198 -0
- package/artemis-main/apps/admin_console/routers/replay.py +91 -0
- package/artemis-main/apps/admin_console/routers/sessions.py +239 -0
- package/artemis-main/apps/admin_console/routers/steps.py +109 -0
- package/artemis-main/apps/admin_console/routers/stream.py +56 -0
- package/artemis-main/apps/admin_console/routers/system.py +761 -0
- package/artemis-main/apps/admin_console/routers/tasks.py +517 -0
- package/artemis-main/apps/admin_console/schemas/__init__.py +13 -0
- package/artemis-main/apps/admin_console/schemas/task_schema.py +47 -0
- package/artemis-main/apps/admin_console/server.py +508 -0
- package/artemis-main/apps/admin_console/services/__init__.py +13 -0
- package/artemis-main/apps/admin_console/services/device_stream_service.py +137 -0
- package/artemis-main/apps/admin_console/services/ipc_service.py +262 -0
- package/artemis-main/apps/admin_console/services/media_service.py +623 -0
- package/artemis-main/apps/admin_console/services/model_service.py +148 -0
- package/artemis-main/apps/admin_console/services/task_preset_catalog.py +514 -0
- package/artemis-main/apps/admin_console/services/task_queue_service.py +1719 -0
- package/artemis-main/apps/admin_console/services/worker_process_io.py +144 -0
- package/artemis-main/apps/showcase_ui/README.md +31 -0
- package/artemis-main/apps/showcase_ui/angular.json +132 -0
- package/artemis-main/apps/showcase_ui/package-lock.json +9472 -0
- package/artemis-main/apps/showcase_ui/package.json +39 -0
- package/artemis-main/apps/showcase_ui/proxy.conf.json +23 -0
- package/artemis-main/apps/showcase_ui/public/favicon.ico +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.png +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.svg +56 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.html +24 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.scss +49 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.spec.ts +42 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.ts +32 -0
- package/artemis-main/apps/showcase_ui/src/app/app.config.ts +29 -0
- package/artemis-main/apps/showcase_ui/src/app/app.routes.ts +27 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream-startup.spec.ts +108 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html +1436 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.scss +3973 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.ts +2235 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.html +380 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.scss +1171 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.ts +270 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.html +433 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.scss +987 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.ts +632 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.html +130 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.scss +406 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.ts +74 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.scss +115 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.ts +52 -0
- package/artemis-main/apps/showcase_ui/src/app/core/data/smart-tasks.data.ts +334 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.spec.ts +55 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.ts +61 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/translate.pipe.ts +11 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/zh-cn.ts +651 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/markdown.model.ts +43 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.spec.ts +47 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.ts +165 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/session.model.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/stream.model.ts +246 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/system.model.ts +118 -0
- package/artemis-main/apps/showcase_ui/src/app/core/services/task-recommendation.service.ts +111 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.html +2130 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.scss +5204 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.ts +1189 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.html +39 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.scss +151 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.ts +58 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.html +201 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.scss +886 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.ts +324 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.spec.ts +418 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.ts +2012 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.spec.ts +173 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.ts +620 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.spec.ts +513 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.ts +1015 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.spec.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.ts +662 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.spec.ts +70 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.ts +383 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.spec.ts +107 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.ts +123 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.spec.ts +92 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.ts +116 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.spec.ts +640 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.ts +1021 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.spec.ts +375 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.ts +1419 -0
- package/artemis-main/apps/showcase_ui/src/index.html +37 -0
- package/artemis-main/apps/showcase_ui/src/main.ts +22 -0
- package/artemis-main/apps/showcase_ui/src/styles.scss +60 -0
- package/artemis-main/apps/showcase_ui/tsconfig.app.json +23 -0
- package/artemis-main/apps/showcase_ui/tsconfig.json +27 -0
- package/artemis-main/apps/showcase_ui/tsconfig.spec.json +23 -0
- package/artemis-main/artemis/__init__.py +44 -0
- package/artemis-main/artemis/__main__.py +18 -0
- package/artemis-main/artemis/_legacy_imports.py +94 -0
- package/artemis-main/artemis/_version.py +30 -0
- package/artemis-main/artemis/agents/__init__.py +17 -0
- package/artemis-main/artemis/agents/checker/checker.json +9 -0
- package/artemis-main/artemis/agents/checker/checker.py +859 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.json +23 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.py +608 -0
- package/artemis-main/artemis/agents/explorer/constants.py +52 -0
- package/artemis-main/artemis/agents/explorer/explorer.json +57 -0
- package/artemis-main/artemis/agents/explorer/explorer.py +473 -0
- package/artemis-main/artemis/agents/explorer/geometry.py +73 -0
- package/artemis-main/artemis/agents/explorer/native_runner.py +878 -0
- package/artemis-main/artemis/agents/explorer/perception_tools.py +632 -0
- package/artemis-main/artemis/agents/explorer/run_setup.py +403 -0
- package/artemis-main/artemis/agents/explorer/screen_index.py +266 -0
- package/artemis-main/artemis/agents/explorer/tiers.py +110 -0
- package/artemis-main/artemis/agents/explorer/tool_declarations.py +394 -0
- package/artemis-main/artemis/agents/explorer/universal_runner.py +317 -0
- package/artemis-main/artemis/agents/flash/context_compressor.py +452 -0
- package/artemis-main/artemis/agents/flash/flash_runner.md +51 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer.md +53 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer_single.md +54 -0
- package/artemis-main/artemis/agents/flash/runner.py +1167 -0
- package/artemis-main/artemis/agents/flash/summarizer.py +511 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.md +8 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.py +182 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.md +74 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.py +322 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.md +15 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.py +403 -0
- package/artemis-main/artemis/agents/log_analyzer/log_reader_sub_agent.md +8 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.md +11 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.py +163 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.json +9 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.py +211 -0
- package/artemis-main/artemis/agents/operator/operator.json +3 -0
- package/artemis-main/artemis/agents/operator/operator.py +1394 -0
- package/artemis-main/artemis/agents/operator/prompts.py +1064 -0
- package/artemis-main/artemis/agents/outputter/outputter.md +36 -0
- package/artemis-main/artemis/agents/outputter/outputter.py +552 -0
- package/artemis-main/artemis/agents/planner/planner.json +32 -0
- package/artemis-main/artemis/agents/planner/planner.py +436 -0
- package/artemis-main/artemis/agents/prompt_assembly.py +79 -0
- package/artemis-main/artemis/agents/summarizer/summarizer.py +190 -0
- package/artemis-main/artemis/agents/validator/action_execution.py +98 -0
- package/artemis-main/artemis/agents/validator/categories.py +33 -0
- package/artemis-main/artemis/agents/validator/execution_loop.py +488 -0
- package/artemis-main/artemis/agents/validator/incidents.py +120 -0
- package/artemis-main/artemis/agents/validator/pixel_safety_net.md +15 -0
- package/artemis-main/artemis/agents/validator/precondition_pixel.py +320 -0
- package/artemis-main/artemis/agents/validator/precondition_xml.py +672 -0
- package/artemis-main/artemis/agents/validator/tool_declarations.py +332 -0
- package/artemis-main/artemis/agents/validator/validator.py +188 -0
- package/artemis-main/artemis/agents/video_analyzer/__init__.py +15 -0
- package/artemis-main/artemis/agents/video_analyzer/audio_native.py +543 -0
- package/artemis-main/artemis/agents/video_analyzer/blackboard.py +821 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_agentic.py +455 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_conversation.py +491 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_native.py +437 -0
- package/artemis-main/artemis/agents/video_analyzer/conflict_resolution.py +137 -0
- package/artemis-main/artemis/agents/video_analyzer/gemini_files.py +162 -0
- package/artemis-main/artemis/agents/video_analyzer/native_coordinator.py +541 -0
- package/artemis-main/artemis/agents/video_analyzer/reliability.py +128 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_engine.py +487 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_tools.py +323 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.md +51 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.py +875 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent.md +15 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent_audio.md +12 -0
- package/artemis-main/artemis/clients/accessibility_client.py +438 -0
- package/artemis-main/artemis/clients/screen_client_factory.py +403 -0
- package/artemis-main/artemis/config/__init__.py +309 -0
- package/artemis-main/artemis/config/agent.py +1098 -0
- package/artemis-main/artemis/config/constants.py +151 -0
- package/artemis-main/artemis/config/core/__init__.py +24 -0
- package/artemis-main/artemis/config/core/engine.py +118 -0
- package/artemis-main/artemis/config/core/interpolator.py +78 -0
- package/artemis-main/artemis/config/llm.py +267 -0
- package/artemis-main/artemis/config/paths.py +244 -0
- package/artemis-main/artemis/config/runtime.py +197 -0
- package/artemis-main/artemis/config/settings.py +315 -0
- package/artemis-main/artemis/constants.py +47 -0
- package/artemis-main/artemis/context.py +289 -0
- package/artemis-main/artemis/controllers/__init__.py +41 -0
- package/artemis-main/artemis/controllers/controller_factory.py +41 -0
- package/artemis-main/artemis/controllers/device_controller.py +29 -0
- package/artemis-main/artemis/controllers/types.py +37 -0
- package/artemis-main/artemis/controllers/unified_controller.py +649 -0
- package/artemis-main/artemis/core/__init__.py +21 -0
- package/artemis-main/artemis/core/diagnostics/__init__.py +90 -0
- package/artemis-main/artemis/core/diagnostics/adb_keys.py +270 -0
- package/artemis-main/artemis/core/diagnostics/adb_server_connection.py +330 -0
- package/artemis-main/artemis/core/diagnostics/device_smoke.py +364 -0
- package/artemis-main/artemis/core/diagnostics/emulator_manager.py +501 -0
- package/artemis-main/artemis/core/diagnostics/engine.py +438 -0
- package/artemis-main/artemis/core/diagnostics/hierarchy_parity.py +216 -0
- package/artemis-main/artemis/core/diagnostics/probes/adb_probe.py +887 -0
- package/artemis-main/artemis/core/diagnostics/probes/base.py +45 -0
- package/artemis-main/artemis/core/diagnostics/probes/credentials_probe.py +296 -0
- package/artemis-main/artemis/core/diagnostics/probes/host_probe.py +427 -0
- package/artemis-main/artemis/core/diagnostics/probes/runtime_probe.py +169 -0
- package/artemis-main/artemis/core/diagnostics/probes/toolchain_probe.py +139 -0
- package/artemis-main/artemis/core/diagnostics/readiness.py +83 -0
- package/artemis-main/artemis/core/diagnostics/schema.py +118 -0
- package/artemis-main/artemis/core/tool_declaration.py +43 -0
- package/artemis-main/artemis/core/tool_failure.py +56 -0
- package/artemis-main/artemis/data_engine/context_vars.py +24 -0
- package/artemis-main/artemis/data_engine/engine.py +1615 -0
- package/artemis-main/artemis/data_engine/history_reader.py +142 -0
- package/artemis-main/artemis/data_engine/models.py +131 -0
- package/artemis-main/artemis/data_engine/storage.py +1245 -0
- package/artemis-main/artemis/data_engine/trace.py +727 -0
- package/artemis-main/artemis/drivers/__init__.py +48 -0
- package/artemis-main/artemis/drivers/android/adb_driver.py +507 -0
- package/artemis-main/artemis/drivers/android/hierarchy.py +64 -0
- package/artemis-main/artemis/drivers/android/input_ime.py +120 -0
- package/artemis-main/artemis/drivers/android/recorder.py +57 -0
- package/artemis-main/artemis/drivers/base.py +290 -0
- package/artemis-main/artemis/drivers/cloud/cloud_driver.py +117 -0
- package/artemis-main/artemis/drivers/factory.py +80 -0
- package/artemis-main/artemis/drivers/mock/mock_driver.py +198 -0
- package/artemis-main/artemis/drivers/types.py +67 -0
- package/artemis-main/artemis/graph/checkpoints.py +1243 -0
- package/artemis-main/artemis/graph/graph.py +1055 -0
- package/artemis-main/artemis/graph/perception.py +234 -0
- package/artemis-main/artemis/graph/state.py +151 -0
- package/artemis-main/artemis/graph/visibility.py +238 -0
- package/artemis-main/artemis/interfaces/cli/__init__.py +19 -0
- package/artemis-main/artemis/interfaces/cli/commands/__init__.py +15 -0
- package/artemis-main/artemis/interfaces/cli/commands/batch.py +278 -0
- package/artemis-main/artemis/interfaces/cli/commands/doctor.py +468 -0
- package/artemis-main/artemis/interfaces/cli/commands/helper.py +226 -0
- package/artemis-main/artemis/interfaces/cli/commands/init.py +193 -0
- package/artemis-main/artemis/interfaces/cli/commands/mcp.py +862 -0
- package/artemis-main/artemis/interfaces/cli/commands/run.py +463 -0
- package/artemis-main/artemis/interfaces/cli/commands/server.py +151 -0
- package/artemis-main/artemis/interfaces/cli/commands/server_lifecycle.py +328 -0
- package/artemis-main/artemis/interfaces/cli/commands/trace.py +111 -0
- package/artemis-main/artemis/interfaces/cli/commands/ui.py +404 -0
- package/artemis-main/artemis/interfaces/cli/main.py +109 -0
- package/artemis-main/artemis/interfaces/sdk/__init__.py +31 -0
- package/artemis-main/artemis/interfaces/sdk/client.py +19 -0
- package/artemis-main/artemis/interfaces/sdk/task.py +72 -0
- package/artemis-main/artemis/llm/__init__.py +25 -0
- package/artemis-main/artemis/llm/fake_model.py +179 -0
- package/artemis-main/artemis/llm/google/__init__.py +57 -0
- package/artemis-main/artemis/llm/google/provider.py +185 -0
- package/artemis-main/artemis/llm/google/usage.py +148 -0
- package/artemis-main/artemis/llm/parser.py +32 -0
- package/artemis-main/artemis/llm/reliability.py +267 -0
- package/artemis-main/artemis/llm/router.py +389 -0
- package/artemis-main/artemis/llm/schemas.py +36 -0
- package/artemis-main/artemis/llm/structured.py +196 -0
- package/artemis-main/artemis/main.py +58 -0
- package/artemis-main/artemis/mcp/__init__.py +20 -0
- package/artemis-main/artemis/mcp/action_executor.py +760 -0
- package/artemis-main/artemis/mcp/action_manifest.py +320 -0
- package/artemis-main/artemis/mcp/action_names.py +172 -0
- package/artemis-main/artemis/mcp/action_server.py +202 -0
- package/artemis-main/artemis/mcp/action_session.py +245 -0
- package/artemis-main/artemis/mcp/action_specs.py +868 -0
- package/artemis-main/artemis/mcp/action_types.py +86 -0
- package/artemis-main/artemis/mcp/actuators/__init__.py +21 -0
- package/artemis-main/artemis/mcp/actuators/adb.py +414 -0
- package/artemis-main/artemis/mcp/actuators/base.py +113 -0
- package/artemis-main/artemis/mcp/actuators/mock.py +70 -0
- package/artemis-main/artemis/mcp/adb_server.py +490 -0
- package/artemis-main/artemis/mcp/observation.py +133 -0
- package/artemis-main/artemis/mcp/xml_search_server.py +297 -0
- package/artemis-main/artemis/memory/__init__.py +90 -0
- package/artemis-main/artemis/memory/chunking.py +1843 -0
- package/artemis-main/artemis/memory/context_policy.py +226 -0
- package/artemis-main/artemis/memory/step_capsule.md +73 -0
- package/artemis-main/artemis/memory/step_memory.py +281 -0
- package/artemis-main/artemis/memory/transcript.py +798 -0
- package/artemis-main/artemis/platform/__init__.py +61 -0
- package/artemis-main/artemis/platform/base.py +104 -0
- package/artemis-main/artemis/platform/darwin.py +184 -0
- package/artemis-main/artemis/platform/linux.py +207 -0
- package/artemis-main/artemis/platform/windows.py +193 -0
- package/artemis-main/artemis/resources/__init__.py +46 -0
- package/artemis-main/artemis/runtime/__init__.py +108 -0
- package/artemis-main/artemis/runtime/adb_endpoint.py +173 -0
- package/artemis-main/artemis/runtime/awake_lease.py +283 -0
- package/artemis-main/artemis/runtime/awake_service.py +343 -0
- package/artemis-main/artemis/runtime/cancel_requests.py +254 -0
- package/artemis-main/artemis/runtime/daemon_client.py +422 -0
- package/artemis-main/artemis/runtime/device_lock.py +1013 -0
- package/artemis-main/artemis/runtime/device_pool.py +478 -0
- package/artemis-main/artemis/runtime/helper_manager.py +1030 -0
- package/artemis-main/artemis/runtime/process_probe.py +98 -0
- package/artemis-main/artemis/runtime/server_lifecycle.py +435 -0
- package/artemis-main/artemis/runtime/supervisor.py +121 -0
- package/artemis-main/artemis/runtime/trace_store.py +375 -0
- package/artemis-main/artemis/sdk/__init__.py +26 -0
- package/artemis-main/artemis/sdk/agent.py +485 -0
- package/artemis-main/artemis/sdk/builders/__init__.py +29 -0
- package/artemis-main/artemis/sdk/builders/agent_config_builder.py +474 -0
- package/artemis-main/artemis/sdk/constants.py +15 -0
- package/artemis-main/artemis/sdk/run_outcome.py +58 -0
- package/artemis-main/artemis/sdk/types/__init__.py +61 -0
- package/artemis-main/artemis/sdk/types/agent.py +89 -0
- package/artemis-main/artemis/sdk/utils.py +28 -0
- package/artemis-main/artemis/services/llm.py +1040 -0
- package/artemis-main/artemis/services/token_meter.py +267 -0
- package/artemis-main/artemis/telemetry/__init__.py +35 -0
- package/artemis-main/artemis/telemetry/models.py +64 -0
- package/artemis-main/artemis/telemetry/replay.py +34 -0
- package/artemis-main/artemis/telemetry/storage/json_storage.py +47 -0
- package/artemis-main/artemis/telemetry/tracer.py +85 -0
- package/artemis-main/artemis/toolchain/__init__.py +52 -0
- package/artemis-main/artemis/toolchain/descriptors.py +92 -0
- package/artemis-main/artemis/toolchain/resolver.py +185 -0
- package/artemis-main/artemis/tools/base.py +232 -0
- package/artemis-main/artemis/tools/command_tool.py +1240 -0
- package/artemis-main/artemis/tools/committee_prompts.json +5 -0
- package/artemis-main/artemis/tools/committee_tool.py +422 -0
- package/artemis-main/artemis/tools/diagnoser_submit_answer_tool.py +87 -0
- package/artemis-main/artemis/tools/diagnostic_tool.py +120 -0
- package/artemis-main/artemis/tools/explorer_tool.py +581 -0
- package/artemis-main/artemis/tools/history/__init__.py +398 -0
- package/artemis-main/artemis/tools/history/replay.py +120 -0
- package/artemis-main/artemis/tools/history/screenshot.py +139 -0
- package/artemis-main/artemis/tools/history/search.py +563 -0
- package/artemis-main/artemis/tools/image_processor_tool.py +124 -0
- package/artemis-main/artemis/tools/index.py +47 -0
- package/artemis-main/artemis/tools/log_tool.py +108 -0
- package/artemis-main/artemis/tools/mobile/launch_app.py +132 -0
- package/artemis-main/artemis/tools/mobile/log_utils.py +138 -0
- package/artemis-main/artemis/tools/mobile/ocr.py +202 -0
- package/artemis-main/artemis/tools/mobile/read_hierarchy.py +108 -0
- package/artemis-main/artemis/tools/mobile/read_logs.py +116 -0
- package/artemis-main/artemis/tools/mobile/search_logs.py +260 -0
- package/artemis-main/artemis/tools/object_detection_tool.py +244 -0
- package/artemis-main/artemis/tools/scratchpad.py +819 -0
- package/artemis-main/artemis/tools/system/adb_shell.py +31 -0
- package/artemis-main/artemis/tools/tool_wrapper.py +270 -0
- package/artemis-main/artemis/tools/video_tool.py +261 -0
- package/artemis-main/artemis/tools/wait_tool.py +97 -0
- package/artemis-main/artemis/utils/app_launch_utils.py +207 -0
- package/artemis-main/artemis/utils/coordinates.py +606 -0
- package/artemis-main/artemis/utils/credentials_validator.py +201 -0
- package/artemis-main/artemis/utils/cv_canvas.py +189 -0
- package/artemis-main/artemis/utils/cython_compat.py +45 -0
- package/artemis-main/artemis/utils/element_hit_test.py +80 -0
- package/artemis-main/artemis/utils/image_diff.py +335 -0
- package/artemis-main/artemis/utils/image_hash.py +80 -0
- package/artemis-main/artemis/utils/notes.py +470 -0
- package/artemis-main/artemis/utils/ocr_api.py +105 -0
- package/artemis-main/artemis/utils/ocr_xml_fusion.py +318 -0
- package/artemis-main/artemis/utils/plan_grammar.py +513 -0
- package/artemis-main/artemis/utils/python_executor.py +213 -0
- package/artemis-main/artemis/utils/startup_progress.py +60 -0
- package/artemis-main/artemis/utils/task_tree.py +1174 -0
- package/artemis-main/artemis/utils/text.py +37 -0
- package/artemis-main/artemis/utils/ui_filter.py +651 -0
- package/artemis-main/artemis/utils/video.py +685 -0
- package/artemis-main/artemis/utils/visualization.py +802 -0
- package/artemis-main/config/artemis.example.jsonc +12 -0
- package/artemis-main/mcp_server/README.md +111 -0
- package/artemis-main/mcp_server/__init__.py +21 -0
- package/artemis-main/mcp_server/__main__.py +20 -0
- package/artemis-main/mcp_server/background/__init__.py +15 -0
- package/artemis-main/mcp_server/background/task_runner.py +453 -0
- package/artemis-main/mcp_server/base.py +49 -0
- package/artemis-main/mcp_server/notifiers/__init__.py +74 -0
- package/artemis-main/mcp_server/notifiers/agentapi.py +289 -0
- package/artemis-main/mcp_server/notifiers/base.py +45 -0
- package/artemis-main/mcp_server/notifiers/composite.py +87 -0
- package/artemis-main/mcp_server/notifiers/desktop.py +108 -0
- package/artemis-main/mcp_server/notifiers/file.py +69 -0
- package/artemis-main/mcp_server/notifiers/script.py +90 -0
- package/artemis-main/mcp_server/notifiers/webhook.py +87 -0
- package/artemis-main/mcp_server/rules.md +68 -0
- package/artemis-main/mcp_server/server.py +106 -0
- package/artemis-main/mcp_server/tools/__init__.py +29 -0
- package/artemis-main/mcp_server/tools/device_state.py +107 -0
- package/artemis-main/mcp_server/tools/diagnose.py +1249 -0
- package/artemis-main/mcp_server/tools/inspect_trace.py +394 -0
- package/artemis-main/mcp_server/tools/task_manager.py +627 -0
- package/artemis-main/mcp_server/tools/task_runner.py +548 -0
- package/artemis-main/mcp_server/utils/__init__.py +15 -0
- package/artemis-main/mcp_server/utils/device_utils.py +180 -0
- package/artemis-main/mcp_server/utils/env_utils.py +65 -0
- package/artemis-main/packages/artemis-accessibility-helper/ArtemisAccessibilityHelper.apk +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/build.gradle.kts +35 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/AndroidManifest.xml +49 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/A11yNode.java +274 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/ArtemisAccessibilityService.java +227 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/CommandServer.java +463 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/DisplayUtils.java +111 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/GestureController.java +232 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/HierarchyDumper.java +832 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenReceiver.java +36 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenStore.java +38 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/XmlUtils.java +102 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/values/strings.xml +4 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/xml/accessibility_service_config.xml +10 -0
- package/artemis-main/packages/artemis-accessibility-helper/build.gradle.kts +3 -0
- package/artemis-main/packages/artemis-accessibility-helper/build_apk.sh +215 -0
- package/artemis-main/packages/artemis-accessibility-helper/debug.keystore +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/gradle.properties +2 -0
- package/artemis-main/packages/artemis-accessibility-helper/helper_manifest.json +7 -0
- package/artemis-main/packages/artemis-accessibility-helper/settings.gradle.kts +17 -0
- package/artemis-main/packages/artemis-client/DESIGN.md +89 -0
- package/artemis-main/packages/artemis-client/README.md +112 -0
- package/artemis-main/packages/artemis-client/examples/basic.py +30 -0
- package/artemis-main/packages/artemis-client/pyproject.toml +36 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/__init__.py +45 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/client.py +401 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/errors.py +66 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/models.py +212 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/py.typed +1 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/transport.py +134 -0
- package/artemis-main/packages/artemis-client/tests/test_client.py +289 -0
- package/artemis-main/packages/artemis-client/tests/test_transport.py +85 -0
- package/artemis-main/pyproject.toml +259 -0
- package/artemis-main/pyright-core.json +17 -0
- package/artemis-main/scripts/check_dependency_sources.py +68 -0
- package/artemis-main/scripts/install_deps.ps1 +520 -0
- package/artemis-main/scripts/install_deps.sh +533 -0
- package/artemis-main/scripts/quality_ratchet.py +97 -0
- package/artemis-main/scripts/real_device_video_acceptance.py +483 -0
- package/artemis-main/scripts/run_edge_case_part.py +327 -0
- package/artemis-main/scripts/run_ui.py +242 -0
- package/artemis-main/scripts/start.ps1 +500 -0
- package/artemis-main/scripts/test_all_edge_cases.py +269 -0
- package/artemis-main/scripts/verify_concurrency_and_devices.py +385 -0
- package/artemis-main/setup.py +164 -0
- package/artemis-main/start.bat +35 -0
- package/artemis-main/start.sh +423 -0
- package/artemis-main/third_party/mobile_use/LICENSE +190 -0
- package/artemis-main/third_party/mobile_use/METADATA +27 -0
- package/artemis-main/third_party/mobile_use/NOTICE +12 -0
- package/artemis-main/third_party/mobile_use/__init__.py +19 -0
- package/artemis-main/third_party/mobile_use/agents/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.md +22 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.py +80 -0
- package/artemis-main/third_party/mobile_use/clients/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/clients/ui_automator_client.py +482 -0
- package/artemis-main/third_party/mobile_use/config/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/config/llm.py +183 -0
- package/artemis-main/third_party/mobile_use/config/output.py +184 -0
- package/artemis-main/third_party/mobile_use/context.py +119 -0
- package/artemis-main/third_party/mobile_use/controllers/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/controllers/platform_specific_commands_controller.py +151 -0
- package/artemis-main/third_party/mobile_use/controllers/types.py +92 -0
- package/artemis-main/third_party/mobile_use/controllers/unified_controller.py +183 -0
- package/artemis-main/third_party/mobile_use/graph.py +54 -0
- package/artemis-main/third_party/mobile_use/llm_service.py +193 -0
- package/artemis-main/third_party/mobile_use/main.py +130 -0
- package/artemis-main/third_party/mobile_use/sdk/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/agent.py +1060 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/agent_config_builder.py +225 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/index.py +33 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/task_request_builder.py +243 -0
- package/artemis-main/third_party/mobile_use/sdk/types/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/types/agent.py +98 -0
- package/artemis-main/third_party/mobile_use/sdk/types/exceptions.py +109 -0
- package/artemis-main/third_party/mobile_use/sdk/types/task.py +234 -0
- package/artemis-main/third_party/mobile_use/testing.py +59 -0
- package/artemis-main/third_party/mobile_use/tools/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/index.py +44 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/launch_app.py +89 -0
- package/artemis-main/third_party/mobile_use/tools/tool_wrapper.py +52 -0
- package/artemis-main/third_party/mobile_use/utils/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/utils/app_launch_utils.py +217 -0
- package/artemis-main/third_party/mobile_use/utils/cli_helpers.py +60 -0
- package/artemis-main/third_party/mobile_use/utils/decorators.py +158 -0
- package/artemis-main/third_party/mobile_use/utils/file.py +31 -0
- package/artemis-main/third_party/mobile_use/utils/logger.py +216 -0
- package/artemis-main/third_party/mobile_use/utils/media.py +213 -0
- package/artemis-main/third_party/mobile_use/utils/shell_utils.py +39 -0
- package/artemis-main/third_party/mobile_use/utils/video.py +398 -0
- package/artemis-main/uv.lock +4908 -0
- package/bin/android-midscene-automation.js +1 -5
- package/bin/artemis-config.mjs +15 -0
- package/bin/artemis-embedded.py +56 -0
- package/bin/start-artemis.mjs +30 -0
- package/bin/start-dev.mjs +112 -0
- package/bin/test_artemis_embedded.py +44 -0
- package/package.json +4 -2
- package/server/artemis.ts +34 -0
- package/server/http-api.ts +12 -0
- package/src/App.vue +10 -5
- package/src/api.ts +5 -0
- package/src/appium-recorder/AppiumPage.vue +1 -1
- package/src/appium-recorder/components/ComponentInspector.vue +1 -1
- package/src/appium-recorder/components/FlowNodeSearch.vue +3 -3
- package/src/appium-recorder/components/ImageCheckDialog.vue +3 -3
- package/src/appium-recorder/components/RecorderWorkspace.vue +4 -4
- package/src/appium-recorder/flow-appearance.ts +4 -4
- package/src/components/AppSidebar.vue +8 -7
- package/src/components/MidsceneMaintenanceNotice.vue +17 -0
- package/src/components/analytics/AnalysisCharts.vue +4 -4
- package/src/components/analytics/ReportAnalysis.vue +1 -1
- package/src/components/generator/TestCaseFileUpload.vue +1 -1
- package/src/components/help/HelpCenter.vue +56 -37
- package/src/pages/AiGeneratorPage.vue +1 -1
- package/src/pages/ArtemisPage.vue +72 -0
- package/src/pages/ConfigPage.vue +18 -19
- package/src/style.css +340 -121
- package/src/types.ts +1 -1
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Copyright 2026 Google LLC
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# Visual styling
|
|
19
|
+
BOLD='\033[1m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
BLUE='\033[0;34m'
|
|
22
|
+
YELLOW='\033[1;33m'
|
|
23
|
+
RED='\033[0;31m'
|
|
24
|
+
CYAN='\033[0;36m'
|
|
25
|
+
DIM='\033[2m'
|
|
26
|
+
NC='\033[0m'
|
|
27
|
+
|
|
28
|
+
AUTO_LAUNCH=false
|
|
29
|
+
for arg in "$@"; do
|
|
30
|
+
case "${arg}" in
|
|
31
|
+
--launch|-l|--open)
|
|
32
|
+
AUTO_LAUNCH=true
|
|
33
|
+
;;
|
|
34
|
+
esac
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
echo -e "${BOLD}${CYAN}======================================================${NC}"
|
|
38
|
+
echo -e "${BOLD}${CYAN} 🚀 Artemis - Smart Multi-Platform Installer ${NC}"
|
|
39
|
+
echo -e "${BOLD}${CYAN}======================================================${NC}"
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
43
|
+
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
44
|
+
cd "${ROOT_DIR}"
|
|
45
|
+
|
|
46
|
+
# Normalize PATH with standard platform binary paths
|
|
47
|
+
STANDARD_PATHS=(
|
|
48
|
+
"/opt/homebrew/bin"
|
|
49
|
+
"/opt/homebrew/sbin"
|
|
50
|
+
"/usr/local/bin"
|
|
51
|
+
"/usr/local/sbin"
|
|
52
|
+
"${HOME}/.local/bin"
|
|
53
|
+
"${HOME}/.local/share/node/bin"
|
|
54
|
+
"${HOME}/.local/share/platform-tools"
|
|
55
|
+
"${HOME}/.local/share/scrcpy"
|
|
56
|
+
"${HOME}/.cargo/bin"
|
|
57
|
+
"${HOME}/Library/Android/sdk/platform-tools"
|
|
58
|
+
"${HOME}/Android/Sdk/platform-tools"
|
|
59
|
+
)
|
|
60
|
+
for p in "${STANDARD_PATHS[@]}"; do
|
|
61
|
+
if [ -d "${p}" ] && [[ ":${PATH}:" != *":${p}:"* ]]; then
|
|
62
|
+
export PATH="${p}:${PATH}"
|
|
63
|
+
fi
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
OS_TYPE="$(uname -s)"
|
|
67
|
+
ARCH_TYPE="$(uname -m)"
|
|
68
|
+
|
|
69
|
+
# Helper to check command availability
|
|
70
|
+
has_cmd() {
|
|
71
|
+
command -v "$1" >/dev/null 2>&1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Sudo credential and choice state tracking
|
|
75
|
+
SUDO_AUTHENTICATED=false
|
|
76
|
+
SUDO_DECLINED=false
|
|
77
|
+
|
|
78
|
+
# Helper to check, prompt for, or skip administrator (sudo) privileges gracefully
|
|
79
|
+
request_sudo() {
|
|
80
|
+
[ "$(id -u)" -eq 0 ] && return 0
|
|
81
|
+
if ! has_cmd sudo; then
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
# If already authenticated or passwordless sudo works
|
|
85
|
+
if [ "${SUDO_AUTHENTICATED}" = true ] || sudo -n true >/dev/null 2>&1; then
|
|
86
|
+
SUDO_AUTHENTICATED=true
|
|
87
|
+
return 0
|
|
88
|
+
fi
|
|
89
|
+
# If previously declined or failed in this session, don't nag again
|
|
90
|
+
if [ "${SUDO_DECLINED}" = true ]; then
|
|
91
|
+
return 1
|
|
92
|
+
fi
|
|
93
|
+
# If interactive terminal, ask user whether to enter sudo password
|
|
94
|
+
if [ -t 0 ]; then
|
|
95
|
+
local action="${1:-install system packages}"
|
|
96
|
+
echo -e " ${CYAN}🔐 Administrator (sudo) privileges can be used to ${action}.${NC}"
|
|
97
|
+
local reply=""
|
|
98
|
+
read -r -p " Enter sudo password now? [Y/n]: " reply
|
|
99
|
+
reply=${reply:-Y}
|
|
100
|
+
if [[ "${reply}" =~ ^[Yy]$ ]]; then
|
|
101
|
+
if sudo -v; then
|
|
102
|
+
SUDO_AUTHENTICATED=true
|
|
103
|
+
echo -e " ${GREEN}✔ Sudo authenticated successfully.${NC}"
|
|
104
|
+
return 0
|
|
105
|
+
else
|
|
106
|
+
echo -e " ${YELLOW}⚠ Sudo authentication failed or cancelled. Using user-space fallback.${NC}"
|
|
107
|
+
SUDO_DECLINED=true
|
|
108
|
+
return 1
|
|
109
|
+
fi
|
|
110
|
+
else
|
|
111
|
+
echo -e " ${YELLOW}⏭️ Skipped sudo. Using user-space fallback.${NC}"
|
|
112
|
+
SUDO_DECLINED=true
|
|
113
|
+
return 1
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
return 1
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Helper to check if Node.js & npm meet Angular CLI 22 requirement (>= 22.22.0, >= 24.15.0, or >= 26.0.0)
|
|
120
|
+
is_node_compatible() {
|
|
121
|
+
if ! has_cmd node || ! has_cmd npm; then
|
|
122
|
+
return 1
|
|
123
|
+
fi
|
|
124
|
+
local node_ver
|
|
125
|
+
node_ver="$(node -v 2>/dev/null | tr -d 'v')"
|
|
126
|
+
[ -z "${node_ver}" ] && return 1
|
|
127
|
+
local major minor
|
|
128
|
+
major="$(echo "${node_ver}" | cut -d. -f1)"
|
|
129
|
+
minor="$(echo "${node_ver}" | cut -d. -f2)"
|
|
130
|
+
if [ "${major}" -ge 26 ] 2>/dev/null; then
|
|
131
|
+
return 0
|
|
132
|
+
elif [ "${major}" -ge 24 ] 2>/dev/null; then
|
|
133
|
+
[ "${minor}" -ge 15 ] 2>/dev/null && return 0
|
|
134
|
+
elif [ "${major}" -ge 22 ] 2>/dev/null; then
|
|
135
|
+
[ "${minor}" -ge 22 ] 2>/dev/null && return 0
|
|
136
|
+
fi
|
|
137
|
+
return 1
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
echo -e "${BOLD}1. Detecting Operating System & Environment...${NC}"
|
|
141
|
+
echo -e " Platform: ${BLUE}${OS_TYPE}${NC} (${ARCH_TYPE})"
|
|
142
|
+
echo -e " Root Dir: ${DIM}${ROOT_DIR}${NC}"
|
|
143
|
+
|
|
144
|
+
# Function to install system toolchains (ADB, FFmpeg, scrcpy)
|
|
145
|
+
install_system_packages() {
|
|
146
|
+
echo -e "\n${BOLD}2. Checking System Toolchains (ADB, FFmpeg, scrcpy)...${NC}"
|
|
147
|
+
|
|
148
|
+
local need_adb=false
|
|
149
|
+
local need_ffmpeg=false
|
|
150
|
+
local need_scrcpy=false
|
|
151
|
+
|
|
152
|
+
if ! has_cmd adb; then
|
|
153
|
+
for candidate in \
|
|
154
|
+
"${ANDROID_HOME:-}/platform-tools" \
|
|
155
|
+
"${ANDROID_SDK_ROOT:-}/platform-tools" \
|
|
156
|
+
"${HOME}/Library/Android/sdk/platform-tools" \
|
|
157
|
+
"${HOME}/Android/Sdk/platform-tools" \
|
|
158
|
+
"${HOME}/.local/share/platform-tools" \
|
|
159
|
+
"/opt/homebrew/bin" \
|
|
160
|
+
"/usr/local/bin"; do
|
|
161
|
+
if [ -n "${candidate}" ] && [ -x "${candidate}/adb" ]; then
|
|
162
|
+
export PATH="${candidate}:${PATH}"
|
|
163
|
+
break
|
|
164
|
+
fi
|
|
165
|
+
done
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
if ! has_cmd adb; then need_adb=true; fi
|
|
169
|
+
if ! has_cmd ffmpeg; then need_ffmpeg=true; fi
|
|
170
|
+
if ! has_cmd scrcpy; then need_scrcpy=true; fi
|
|
171
|
+
|
|
172
|
+
if [ "${need_adb}" = false ] && [ "${need_ffmpeg}" = false ] && [ "${need_scrcpy}" = false ]; then
|
|
173
|
+
echo -e " ${GREEN}✓ All core system tools are already installed.${NC}"
|
|
174
|
+
if has_cmd adb; then
|
|
175
|
+
(unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true)
|
|
176
|
+
fi
|
|
177
|
+
return 0
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
echo -e " ${YELLOW}! Missing toolchains detected:${NC}"
|
|
181
|
+
[ "${need_adb}" = true ] && echo -e " • [ADB] Android Debug Bridge"
|
|
182
|
+
[ "${need_ffmpeg}" = true ] && echo -e " • [FFmpeg] Video encoding/trimming framework"
|
|
183
|
+
[ "${need_scrcpy}" = true ] && echo -e " • [scrcpy] Real-time Android screen mirroring"
|
|
184
|
+
|
|
185
|
+
echo -e " Attempting automated installation..."
|
|
186
|
+
|
|
187
|
+
if [ "${OS_TYPE}" = "Darwin" ]; then
|
|
188
|
+
# Ensure Homebrew environment variables to prevent hanging
|
|
189
|
+
export HOMEBREW_NO_AUTO_UPDATE=1
|
|
190
|
+
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
|
191
|
+
export HOMEBREW_NO_ENV_HINTS=1
|
|
192
|
+
|
|
193
|
+
if ! has_cmd brew; then
|
|
194
|
+
if [ -x "/opt/homebrew/bin/brew" ]; then
|
|
195
|
+
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
196
|
+
elif [ -x "/usr/local/bin/brew" ]; then
|
|
197
|
+
eval "$(/usr/local/bin/brew shellenv)"
|
|
198
|
+
fi
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
if has_cmd brew; then
|
|
202
|
+
echo -e " ${CYAN}Detected Homebrew ($(brew --version | head -n1)). Installing missing components...${NC}"
|
|
203
|
+
if [ "${need_adb}" = true ]; then
|
|
204
|
+
echo -e " 📦 Installing ${BOLD}android-platform-tools${NC}..."
|
|
205
|
+
brew install --cask android-platform-tools || brew install android-platform-tools || true
|
|
206
|
+
fi
|
|
207
|
+
if [ "${need_ffmpeg}" = true ]; then
|
|
208
|
+
echo -e " 📦 Installing ${BOLD}ffmpeg${NC}..."
|
|
209
|
+
brew install ffmpeg || true
|
|
210
|
+
fi
|
|
211
|
+
if [ "${need_scrcpy}" = true ]; then
|
|
212
|
+
echo -e " 📦 Installing ${BOLD}scrcpy${NC}..."
|
|
213
|
+
brew install scrcpy || true
|
|
214
|
+
fi
|
|
215
|
+
else
|
|
216
|
+
echo -e " ${YELLOW}⚠ Homebrew not found. Please install Homebrew or install tools manually:${NC}"
|
|
217
|
+
echo -e " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
218
|
+
echo -e " brew install --cask android-platform-tools && brew install ffmpeg scrcpy"
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
elif [ "${OS_TYPE}" = "Linux" ]; then
|
|
222
|
+
local PKGS=()
|
|
223
|
+
[ "${need_adb}" = true ] && PKGS+=("adb")
|
|
224
|
+
[ "${need_ffmpeg}" = true ] && PKGS+=("ffmpeg")
|
|
225
|
+
[ "${need_scrcpy}" = true ] && PKGS+=("scrcpy")
|
|
226
|
+
|
|
227
|
+
if request_sudo "install missing system components (${PKGS[*]})"; then
|
|
228
|
+
local SUDO_PREFIX=""
|
|
229
|
+
if [ "$(id -u)" -ne 0 ]; then
|
|
230
|
+
SUDO_PREFIX="sudo"
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
if has_cmd apt-get; then
|
|
234
|
+
echo -e " ${CYAN}Detected Debian/Ubuntu (apt-get). Installing missing packages...${NC}"
|
|
235
|
+
DEBIAN_FRONTEND=noninteractive ${SUDO_PREFIX} apt-get -o DPkg::Lock::Timeout=3 -o Acquire::http::Timeout=3 -o Acquire::https::Timeout=3 install -y "${PKGS[@]}" 2>/dev/null || true
|
|
236
|
+
elif has_cmd dnf; then
|
|
237
|
+
echo -e " ${CYAN}Detected Fedora/RHEL (dnf). Installing packages...${NC}"
|
|
238
|
+
local DNF_PKGS=()
|
|
239
|
+
[ "${need_adb}" = true ] && DNF_PKGS+=("android-tools")
|
|
240
|
+
[ "${need_ffmpeg}" = true ] && DNF_PKGS+=("ffmpeg")
|
|
241
|
+
[ "${need_scrcpy}" = true ] && DNF_PKGS+=("scrcpy")
|
|
242
|
+
${SUDO_PREFIX} dnf install -y "${DNF_PKGS[@]}" 2>/dev/null || true
|
|
243
|
+
elif has_cmd pacman; then
|
|
244
|
+
echo -e " ${CYAN}Detected Arch Linux (pacman). Installing packages...${NC}"
|
|
245
|
+
local PAC_PKGS=()
|
|
246
|
+
[ "${need_adb}" = true ] && PAC_PKGS+=("android-tools")
|
|
247
|
+
[ "${need_ffmpeg}" = true ] && PAC_PKGS+=("ffmpeg")
|
|
248
|
+
[ "${need_scrcpy}" = true ] && PAC_PKGS+=("scrcpy")
|
|
249
|
+
${SUDO_PREFIX} pacman -S --noconfirm "${PAC_PKGS[@]}" 2>/dev/null || true
|
|
250
|
+
fi
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
# Fallback: if scrcpy is still missing, install official precompiled portable scrcpy in user space
|
|
254
|
+
if ! has_cmd scrcpy; then
|
|
255
|
+
local SCRCPY_ARCH=""
|
|
256
|
+
case "${ARCH_TYPE}" in
|
|
257
|
+
x86_64|amd64) SCRCPY_ARCH="x86_64" ;;
|
|
258
|
+
aarch64|arm64) SCRCPY_ARCH="aarch64" ;;
|
|
259
|
+
esac
|
|
260
|
+
if [ -n "${SCRCPY_ARCH}" ]; then
|
|
261
|
+
local SCRCPY_DIR="${HOME}/.local/share/scrcpy"
|
|
262
|
+
if [ ! -x "${SCRCPY_DIR}/scrcpy" ]; then
|
|
263
|
+
echo -e " ${CYAN}📦 Installing portable scrcpy in user space (~/.local)...${NC}"
|
|
264
|
+
mkdir -p "${SCRCPY_DIR}" "${HOME}/.local/bin"
|
|
265
|
+
local SCRCPY_URL="https://github.com/Genymobile/scrcpy/releases/download/v4.1/scrcpy-linux-${SCRCPY_ARCH}-v4.1.tar.gz"
|
|
266
|
+
if curl -fsSL --connect-timeout 5 --max-time 30 "${SCRCPY_URL}" | tar -xz -C "${SCRCPY_DIR}" --strip-components=1 2>/dev/null; then
|
|
267
|
+
ln -sf "${SCRCPY_DIR}/scrcpy" "${HOME}/.local/bin/scrcpy"
|
|
268
|
+
export PATH="${SCRCPY_DIR}:${PATH}"
|
|
269
|
+
echo -e " ${GREEN}✓ scrcpy installed in user space.${NC}"
|
|
270
|
+
fi
|
|
271
|
+
else
|
|
272
|
+
ln -sf "${SCRCPY_DIR}/scrcpy" "${HOME}/.local/bin/scrcpy"
|
|
273
|
+
export PATH="${SCRCPY_DIR}:${PATH}"
|
|
274
|
+
fi
|
|
275
|
+
fi
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
# User-space fallback for adb if missing and no root privileges
|
|
279
|
+
if ! has_cmd adb; then
|
|
280
|
+
if [[ "${ARCH_TYPE}" = "x86_64" || "${ARCH_TYPE}" = "amd64" ]]; then
|
|
281
|
+
local PT_DIR="${HOME}/.local/share/platform-tools"
|
|
282
|
+
if [ ! -x "${PT_DIR}/adb" ]; then
|
|
283
|
+
echo -e " ${CYAN}📦 Installing Android platform-tools (adb) in user space...${NC}"
|
|
284
|
+
local TEMP_ZIP="/tmp/platform-tools-$$.zip"
|
|
285
|
+
if curl -fsSL --connect-timeout 5 --max-time 30 "https://dl.google.com/android/repository/platform-tools-latest-linux.zip" -o "${TEMP_ZIP}" 2>/dev/null; then
|
|
286
|
+
mkdir -p "${HOME}/.local/share" "${HOME}/.local/bin"
|
|
287
|
+
if has_cmd unzip; then
|
|
288
|
+
unzip -q -o "${TEMP_ZIP}" -d "${HOME}/.local/share" 2>/dev/null || true
|
|
289
|
+
else
|
|
290
|
+
python3 -m zipfile -e "${TEMP_ZIP}" "${HOME}/.local/share" 2>/dev/null || true
|
|
291
|
+
fi
|
|
292
|
+
rm -f "${TEMP_ZIP}"
|
|
293
|
+
fi
|
|
294
|
+
fi
|
|
295
|
+
if [ -x "${PT_DIR}/adb" ]; then
|
|
296
|
+
ln -sf "${PT_DIR}/adb" "${HOME}/.local/bin/adb"
|
|
297
|
+
export PATH="${PT_DIR}:${PATH}"
|
|
298
|
+
echo -e " ${GREEN}✓ adb installed in user space.${NC}"
|
|
299
|
+
fi
|
|
300
|
+
fi
|
|
301
|
+
fi
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
# Ensure local ADB daemon is warm & listening
|
|
305
|
+
if has_cmd adb; then
|
|
306
|
+
(unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true)
|
|
307
|
+
fi
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Function to ensure uv is installed and ready
|
|
311
|
+
ensure_uv() {
|
|
312
|
+
echo -e "\n${BOLD}3. Checking Python Package Manager (uv)...${NC}"
|
|
313
|
+
if ! has_cmd uv; then
|
|
314
|
+
echo -e " ${YELLOW}uv not found. Installing Astral uv (ultra-fast Python package manager)...${NC}"
|
|
315
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
316
|
+
export PATH="${HOME}/.local/bin:${HOME}/.cargo/bin:${PATH}"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
# Explicitly persist PATH to shell configuration files if not present
|
|
320
|
+
local export_line='export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"'
|
|
321
|
+
for rc in "${HOME}/.bashrc" "${HOME}/.zshrc" "${HOME}/.profile"; do
|
|
322
|
+
if [ -f "${rc}" ]; then
|
|
323
|
+
if ! grep -qs 'HOME/\.local/bin' "${rc}"; then
|
|
324
|
+
echo -e "\n# Added by Artemis installer\n${export_line}" >> "${rc}"
|
|
325
|
+
fi
|
|
326
|
+
fi
|
|
327
|
+
done
|
|
328
|
+
|
|
329
|
+
# If /usr/local/bin is writable or sudo is available, try to create a symlink to make it available immediately
|
|
330
|
+
local uv_bin=""
|
|
331
|
+
if [ -x "${HOME}/.local/bin/uv" ]; then
|
|
332
|
+
uv_bin="${HOME}/.local/bin/uv"
|
|
333
|
+
elif command -v uv >/dev/null 2>&1; then
|
|
334
|
+
uv_bin="$(command -v uv)"
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
if [ -n "${uv_bin}" ]; then
|
|
338
|
+
if [ -w "/usr/local/bin" ]; then
|
|
339
|
+
ln -sf "${uv_bin}" /usr/local/bin/uv 2>/dev/null || true
|
|
340
|
+
[ -x "${HOME}/.local/bin/uvx" ] && ln -sf "${HOME}/.local/bin/uvx" /usr/local/bin/uvx 2>/dev/null || true
|
|
341
|
+
elif has_cmd sudo; then
|
|
342
|
+
sudo -n ln -sf "${uv_bin}" /usr/local/bin/uv 2>/dev/null || true
|
|
343
|
+
[ -x "${HOME}/.local/bin/uvx" ] && sudo -n ln -sf "${HOME}/.local/bin/uvx" /usr/local/bin/uvx 2>/dev/null || true
|
|
344
|
+
fi
|
|
345
|
+
fi
|
|
346
|
+
|
|
347
|
+
if has_cmd uv; then
|
|
348
|
+
echo -e " ${GREEN}✓ uv is ready ($(uv --version))${NC}"
|
|
349
|
+
else
|
|
350
|
+
echo -e " ${RED}✗ Failed to find uv in PATH. Please add ~/.local/bin to your PATH.${NC}"
|
|
351
|
+
exit 1
|
|
352
|
+
fi
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
# Function to setup Python runtime and sync dependencies
|
|
356
|
+
setup_python_env() {
|
|
357
|
+
echo -e "\n${BOLD}4. Configuring Python Runtime & Syncing Dependencies...${NC}"
|
|
358
|
+
echo -e " ${BLUE}📦 Running uv sync (auto-provisioning Python >=3.12 & dependencies)...${NC}"
|
|
359
|
+
uv sync
|
|
360
|
+
echo -e " ${GREEN}✓ Python runtime and dependencies synced successfully.${NC}"
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
# Function to initialize .env configuration
|
|
364
|
+
setup_env_file() {
|
|
365
|
+
echo -e "\n${BOLD}5. Checking Environment Configuration (.env)...${NC}"
|
|
366
|
+
if [ ! -f ".env" ]; then
|
|
367
|
+
if [ -f ".env.example" ]; then
|
|
368
|
+
cp .env.example .env
|
|
369
|
+
echo -e " ${GREEN}✓ Created .env template from .env.example.${NC}"
|
|
370
|
+
else
|
|
371
|
+
touch .env
|
|
372
|
+
echo -e " ${GREEN}✓ Created empty .env file.${NC}"
|
|
373
|
+
fi
|
|
374
|
+
else
|
|
375
|
+
echo -e " ${GREEN}✓ .env configuration file exists.${NC}"
|
|
376
|
+
fi
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
# Function to check and build Showcase UI
|
|
380
|
+
setup_showcase_ui() {
|
|
381
|
+
echo -e "\n${BOLD}6. Checking Showcase UI Build (Angular)...${NC}"
|
|
382
|
+
local SHOWCASE_INDEX="${ROOT_DIR}/apps/showcase_ui/dist/frontend/browser/index.html"
|
|
383
|
+
local SHOWCASE_INDEX_ALT1="${ROOT_DIR}/apps/showcase_ui/dist/browser/index.html"
|
|
384
|
+
local SHOWCASE_INDEX_ALT2="${ROOT_DIR}/apps/showcase_ui/dist/index.html"
|
|
385
|
+
if [ ! -f "${SHOWCASE_INDEX}" ] && [ ! -f "${SHOWCASE_INDEX_ALT1}" ] && [ ! -f "${SHOWCASE_INDEX_ALT2}" ]; then
|
|
386
|
+
# Try loading nvm if available in user environment
|
|
387
|
+
export NVM_DIR="${HOME}/.nvm"
|
|
388
|
+
if [ -s "${NVM_DIR}/nvm.sh" ]; then
|
|
389
|
+
# shellcheck disable=SC1090,SC1091
|
|
390
|
+
. "${NVM_DIR}/nvm.sh" 2>/dev/null || true
|
|
391
|
+
fi
|
|
392
|
+
if [ -d "${HOME}/.local/share/node/bin" ] && [[ ":${PATH}:" != *":${HOME}/.local/share/node/bin:"* ]]; then
|
|
393
|
+
export PATH="${HOME}/.local/share/node/bin:${PATH}"
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
# Check if nvm already has a compatible Node version installed
|
|
397
|
+
if ! is_node_compatible && (command -v nvm >/dev/null 2>&1 || type nvm >/dev/null 2>&1); then
|
|
398
|
+
nvm use 22 >/dev/null 2>&1 || true
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
if ! is_node_compatible; then
|
|
402
|
+
if has_cmd node; then
|
|
403
|
+
local current_node="$(node -v 2>/dev/null)"
|
|
404
|
+
echo -e " ${YELLOW}⚡ Detected Node.js ${current_node}, but Angular CLI requires Node.js >= v22.22.0. Upgrading Node.js...${NC}"
|
|
405
|
+
else
|
|
406
|
+
echo -e " ${YELLOW}⚡ Node.js/npm not found. Auto-installing Node.js 22 LTS for Showcase UI compilation...${NC}"
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
# 1. Try installing Node 22 via nvm if available
|
|
410
|
+
if command -v nvm >/dev/null 2>&1 || type nvm >/dev/null 2>&1; then
|
|
411
|
+
echo -e " ${CYAN}📦 Installing Node.js 22 LTS via nvm...${NC}"
|
|
412
|
+
nvm install 22 >/dev/null 2>&1 || true
|
|
413
|
+
nvm use 22 >/dev/null 2>&1 || true
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
# 2. Try brew on macOS
|
|
417
|
+
if ! is_node_compatible && [ "${OS_TYPE}" = "Darwin" ] && has_cmd brew; then
|
|
418
|
+
brew install node >/dev/null 2>&1 || brew upgrade node >/dev/null 2>&1 || true
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
# 3. Try Linux package managers with sudo / root
|
|
422
|
+
if ! is_node_compatible && [ "${OS_TYPE}" = "Linux" ]; then
|
|
423
|
+
if request_sudo "install or upgrade Node.js to >= 22.22.0"; then
|
|
424
|
+
local SUDO_PREFIX=""
|
|
425
|
+
if [ "$(id -u)" -ne 0 ]; then SUDO_PREFIX="sudo"; fi
|
|
426
|
+
if has_cmd apt-get; then
|
|
427
|
+
echo -e " ${CYAN}📦 Configuring NodeSource Node.js 22 LTS repository...${NC}"
|
|
428
|
+
curl -fsSL --connect-timeout 5 --max-time 30 https://deb.nodesource.com/setup_22.x | ${SUDO_PREFIX} bash - >/dev/null 2>&1 || true
|
|
429
|
+
${SUDO_PREFIX} apt-get -o DPkg::Lock::Timeout=5 install -y -qq nodejs 2>/dev/null || true
|
|
430
|
+
elif has_cmd dnf; then
|
|
431
|
+
curl -fsSL --connect-timeout 5 --max-time 30 https://rpm.nodesource.com/setup_22.x | ${SUDO_PREFIX} bash - >/dev/null 2>&1 || true
|
|
432
|
+
${SUDO_PREFIX} dnf install -y nodejs || true
|
|
433
|
+
elif has_cmd pacman; then
|
|
434
|
+
${SUDO_PREFIX} pacman -S --noconfirm nodejs npm || true
|
|
435
|
+
fi
|
|
436
|
+
fi
|
|
437
|
+
fi
|
|
438
|
+
|
|
439
|
+
# 4. Standalone portable Node.js LTS (zero-admin user space fallback, guaranteed compatible)
|
|
440
|
+
if ! is_node_compatible; then
|
|
441
|
+
local ARCH="$(uname -m)"
|
|
442
|
+
local NODE_ARCH=""
|
|
443
|
+
case "${ARCH}" in
|
|
444
|
+
x86_64|amd64) NODE_ARCH="x64" ;;
|
|
445
|
+
aarch64|arm64) NODE_ARCH="arm64" ;;
|
|
446
|
+
esac
|
|
447
|
+
local OS_SYS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
448
|
+
if [ -n "${NODE_ARCH}" ] && { [ "${OS_SYS}" = "linux" ] || [ "${OS_SYS}" = "darwin" ]; }; then
|
|
449
|
+
local NODE_VER="v22.23.2"
|
|
450
|
+
local NODE_DIR="${HOME}/.local/share/node"
|
|
451
|
+
echo -e " ${CYAN}📦 Installing portable Node.js ${NODE_VER} in user space (~/.local)...${NC}"
|
|
452
|
+
rm -rf "${NODE_DIR}"
|
|
453
|
+
mkdir -p "${NODE_DIR}" "${HOME}/.local/bin"
|
|
454
|
+
if curl -fsSL --connect-timeout 5 --max-time 60 "https://nodejs.org/dist/${NODE_VER}/node-${NODE_VER}-${OS_SYS}-${NODE_ARCH}.tar.gz" | tar -xz -C "${NODE_DIR}" --strip-components=1 2>/dev/null; then
|
|
455
|
+
ln -sf "${NODE_DIR}/bin/node" "${HOME}/.local/bin/node"
|
|
456
|
+
ln -sf "${NODE_DIR}/bin/npm" "${HOME}/.local/bin/npm"
|
|
457
|
+
ln -sf "${NODE_DIR}/bin/npx" "${HOME}/.local/bin/npx"
|
|
458
|
+
export PATH="${NODE_DIR}/bin:${HOME}/.local/bin:${PATH}"
|
|
459
|
+
hash -r 2>/dev/null || true
|
|
460
|
+
echo -e " ${GREEN}✓ Portable Node.js ${NODE_VER} installed in user space.${NC}"
|
|
461
|
+
fi
|
|
462
|
+
fi
|
|
463
|
+
fi
|
|
464
|
+
fi
|
|
465
|
+
|
|
466
|
+
if is_node_compatible; then
|
|
467
|
+
echo -e " ${GREEN}✓ Node.js $(node -v 2>/dev/null) and npm $(npm -v 2>/dev/null) ready.${NC}"
|
|
468
|
+
echo -e " ${YELLOW}🎨 Building Angular Showcase UI...${NC}"
|
|
469
|
+
(
|
|
470
|
+
cd "${ROOT_DIR}/apps/showcase_ui"
|
|
471
|
+
npm install --silent
|
|
472
|
+
CLI_NODE_VERSION="${ROOT_DIR}/apps/showcase_ui/node_modules/@angular/cli/src/utilities/node-version.js"
|
|
473
|
+
if [ -f "${CLI_NODE_VERSION}" ]; then
|
|
474
|
+
if [ "${OS_TYPE}" = "Darwin" ]; then
|
|
475
|
+
sed -i '' 's/22\.22\.3/22.22.0/g' "${CLI_NODE_VERSION}" 2>/dev/null || true
|
|
476
|
+
else
|
|
477
|
+
sed -i 's/22\.22\.3/22.22.0/g' "${CLI_NODE_VERSION}" 2>/dev/null || true
|
|
478
|
+
fi
|
|
479
|
+
fi
|
|
480
|
+
npm run build
|
|
481
|
+
)
|
|
482
|
+
echo -e " ${GREEN}✓ Showcase UI compiled successfully.${NC}"
|
|
483
|
+
else
|
|
484
|
+
echo -e " ${YELLOW}⚠ Could not configure compatible Node.js (>= 22.22.0). Showcase UI will show fallback notice on launch.${NC}"
|
|
485
|
+
fi
|
|
486
|
+
else
|
|
487
|
+
echo -e " ${GREEN}✓ Showcase UI build already exists.${NC}"
|
|
488
|
+
fi
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
# Function to display system readiness report
|
|
492
|
+
verify_readiness() {
|
|
493
|
+
echo -e "\n${BOLD}7. Toolchain Readiness Summary:${NC}"
|
|
494
|
+
|
|
495
|
+
local tools=("adb" "ffmpeg" "scrcpy" "uv" "python3" "npm")
|
|
496
|
+
for t in "${tools[@]}"; do
|
|
497
|
+
if has_cmd "$t"; then
|
|
498
|
+
local loc
|
|
499
|
+
loc="$(command -v "$t")"
|
|
500
|
+
if [ "$t" = "npm" ] && has_cmd node; then
|
|
501
|
+
local n_ver
|
|
502
|
+
n_ver="$(node -v 2>/dev/null || echo '')"
|
|
503
|
+
echo -e " ${GREEN}✔ ${t}${NC} (${n_ver}) -> ${DIM}${loc}${NC}"
|
|
504
|
+
else
|
|
505
|
+
echo -e " ${GREEN}✔ ${t}${NC} -> ${DIM}${loc}${NC}"
|
|
506
|
+
fi
|
|
507
|
+
else
|
|
508
|
+
echo -e " ${YELLOW}○ ${t}${NC} -> ${YELLOW}Not found in PATH (Fallbacks active)${NC}"
|
|
509
|
+
fi
|
|
510
|
+
done
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
# Run setup workflow
|
|
514
|
+
install_system_packages
|
|
515
|
+
ensure_uv
|
|
516
|
+
setup_python_env
|
|
517
|
+
setup_env_file
|
|
518
|
+
setup_showcase_ui
|
|
519
|
+
verify_readiness
|
|
520
|
+
|
|
521
|
+
echo -e "\n${BOLD}${CYAN}======================================================${NC}"
|
|
522
|
+
echo -e "${BOLD}${GREEN} ✨ Artemis Environment Ready! ${NC}"
|
|
523
|
+
echo -e "${BOLD}${CYAN}======================================================${NC}"
|
|
524
|
+
|
|
525
|
+
if [ "${AUTO_LAUNCH}" = true ]; then
|
|
526
|
+
echo -e "\n${GREEN}🚀 Auto-launching Showcase UI...${NC}"
|
|
527
|
+
exec uv run artemis ui --open
|
|
528
|
+
else
|
|
529
|
+
echo -e "To launch the unified UI & live device onboarding:"
|
|
530
|
+
echo -e " 👉 ${BOLD}${CYAN}./start.sh${NC} (Recommended - automatically sets up environment)"
|
|
531
|
+
echo -e " 👉 ${BOLD}source ~/.bashrc && uv run artemis ui${NC} (or open a new terminal tab)"
|
|
532
|
+
echo ""
|
|
533
|
+
fi
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Fail CI when exception-handler or type-ignore counts exceed the baseline.
|
|
2
|
+
|
|
3
|
+
Lower the committed baseline when removing existing debt.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import ast
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
import re
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
17
|
+
SOURCE_ROOTS = (
|
|
18
|
+
ROOT / "artemis",
|
|
19
|
+
ROOT / "mcp_server",
|
|
20
|
+
ROOT / "apps" / "admin_console",
|
|
21
|
+
ROOT / "third_party",
|
|
22
|
+
)
|
|
23
|
+
BASELINE_PATH = ROOT / ".quality-baseline.json"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _exception_names(node: ast.expr | None) -> set[str]:
|
|
27
|
+
if node is None:
|
|
28
|
+
return {"bare-except"}
|
|
29
|
+
if isinstance(node, ast.Name):
|
|
30
|
+
return {node.id}
|
|
31
|
+
if isinstance(node, ast.Attribute):
|
|
32
|
+
return {node.attr}
|
|
33
|
+
if isinstance(node, ast.Tuple):
|
|
34
|
+
names: set[str] = set()
|
|
35
|
+
for child in node.elts:
|
|
36
|
+
names.update(_exception_names(child))
|
|
37
|
+
return names
|
|
38
|
+
return set()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def collect_metrics() -> dict[str, int]:
|
|
42
|
+
metrics = {
|
|
43
|
+
"broad_exception_handlers": 0,
|
|
44
|
+
"silent_broad_exception_handlers": 0,
|
|
45
|
+
"type_ignore_comments": 0,
|
|
46
|
+
}
|
|
47
|
+
for source_root in SOURCE_ROOTS:
|
|
48
|
+
for path in source_root.rglob("*.py"):
|
|
49
|
+
text = path.read_text(encoding="utf-8-sig")
|
|
50
|
+
metrics["type_ignore_comments"] += len(re.findall(r"#\s*type:\s*ignore\b", text))
|
|
51
|
+
try:
|
|
52
|
+
tree = ast.parse(text, filename=str(path))
|
|
53
|
+
except SyntaxError as exc:
|
|
54
|
+
raise RuntimeError(f"Cannot inspect invalid Python file {path}: {exc}") from exc
|
|
55
|
+
for node in ast.walk(tree):
|
|
56
|
+
if not isinstance(node, ast.ExceptHandler):
|
|
57
|
+
continue
|
|
58
|
+
names = _exception_names(node.type)
|
|
59
|
+
if not names.intersection({"Exception", "BaseException", "bare-except"}):
|
|
60
|
+
continue
|
|
61
|
+
metrics["broad_exception_handlers"] += 1
|
|
62
|
+
if node.body and all(isinstance(statement, ast.Pass) for statement in node.body):
|
|
63
|
+
metrics["silent_broad_exception_handlers"] += 1
|
|
64
|
+
return metrics
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main() -> int:
|
|
68
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
69
|
+
parser.add_argument("--print-current", action="store_true", help="print metrics as JSON")
|
|
70
|
+
args = parser.parse_args()
|
|
71
|
+
|
|
72
|
+
current = collect_metrics()
|
|
73
|
+
if args.print_current:
|
|
74
|
+
print(json.dumps(current, indent=2, sort_keys=True))
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
baseline = json.loads(BASELINE_PATH.read_text(encoding="utf-8"))
|
|
78
|
+
regressions = {
|
|
79
|
+
name: (baseline[name], value)
|
|
80
|
+
for name, value in current.items()
|
|
81
|
+
if value > int(baseline[name])
|
|
82
|
+
}
|
|
83
|
+
if regressions:
|
|
84
|
+
for name, (allowed, actual) in regressions.items():
|
|
85
|
+
print(f"quality regression: {name} increased from {allowed} to {actual}")
|
|
86
|
+
return 1
|
|
87
|
+
|
|
88
|
+
print("quality ratchet passed")
|
|
89
|
+
for name, value in current.items():
|
|
90
|
+
improvement = int(baseline[name]) - value
|
|
91
|
+
suffix = f" ({improvement} below baseline)" if improvement else ""
|
|
92
|
+
print(f" {name}: {value}{suffix}")
|
|
93
|
+
return 0
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
sys.exit(main())
|