ok-script 2.0.18__tar.gz → 2.0.20__tar.gz
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.
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/develop/SKILL.md +9 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/generate-templates/SKILL.md +17 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/setup-env/SKILL.md +29 -1
- ok_script-2.0.20/.agents/skills/setup-env/assets/ok-script-develop/SKILL.md +84 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/setup-project/SKILL.md +6 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/write-test/SKILL.md +10 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/PKG-INFO +3 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/README.md +2 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/docs/agent-setup.md +21 -7
- {ok_script-2.0.18 → ok_script-2.0.20}/docs/feature-crops.md +13 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/docs/mcp.md +7 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/nemu_ipc.py +8 -5
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/mcp_server.py +8 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/base.py +2 -2
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/nemu_ipc.py +10 -3
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/keys.py +30 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/post_message.py +24 -2
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/pydirect.py +26 -7
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/pynput.py +13 -9
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/task/TaskExecutor.py +10 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/task/task.py +2 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/test/__init__.py +4 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/AboutTab.py +2 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/en_US.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/en_US.ts +8 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/es_ES.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/es_ES.ts +8 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/ja_JP.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/ja_JP.ts +9 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/ko_KR.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/ko_KR.ts +9 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/zh_CN.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/zh_CN.ts +8 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/zh_TW.qm +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/zh_TW.ts +8 -0
- ok_script-2.0.20/ok/ui/qt/resources.py +17921 -0
- ok_script-2.0.20/ok/ui/qt/tasks/LabelAndLineEdit.py +83 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/window.py +4 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/PKG-INFO +3 -1
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/SOURCES.txt +3 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_mcp_runner.py +1 -1
- ok_script-2.0.20/tests/test_mouse_buttons.py +205 -0
- ok_script-2.0.20/tests/test_nemu_ipc_capture.py +84 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_skills.py +2 -0
- ok_script-2.0.20/tests/test_task_executor_next_frame.py +83 -0
- ok_script-2.0.18/ok/ui/qt/resources.py +0 -17886
- ok_script-2.0.18/ok/ui/qt/tasks/LabelAndLineEdit.py +0 -39
- ok_script-2.0.18/tests/test_nemu_ipc_capture.py +0 -40
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/develop/agents/openai.yaml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/develop/references/windows-input.md +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/reload-tasks/SKILL.md +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/reload-tasks/agents/openai.yaml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/setup-env/agents/openai.yaml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/setup-project/agents/openai.yaml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/use_venv/SKILL.md +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/.agents/skills/write-test/agents/openai.yaml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/LICENSE.txt +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/MANIFEST.in +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/diagnostics/qq_trace.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/examples/mcp_observe.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/__main__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/alas/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/alas/emulator_base.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/alas/emulator_windows.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/alas/platform_windows.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/alas/utils.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/assets/default-icon.png +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/deep.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/minitouch.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/nemu_utils.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/pool.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/timer.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/adb/util.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/windows/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/windows/d3d11.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/capture/windows/dump.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/cli.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/capture_labels.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/code_runner.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/config_schema.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/downloads.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/events.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/icons.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/mcp_runner.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/notifications.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/plugin_staging.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/plugins.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/screenshot.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/script_editing.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/script_packager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/script_templates.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/skills.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/start_controller.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/task_manager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/template_store.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/translation.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/core/ui_config.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/DeviceManager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/adb.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/bitblt.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/bitblt_utils.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/browser.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/desktop_duplication.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/hwnd_window.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/image.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/types.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/update.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/windows_graphics.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/capture_methods/windows_graphics_hdr.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/adb.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/base.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/browser.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/do_nothing.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/foreground_post_message.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/genshin.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/interaction_methods/swipe.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/device/intercation.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/feature/Box.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/feature/Feature.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/feature/FeatureSet.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/feature/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/gui/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/gui/util/pyappify_startup.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/manager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/messenger_images.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/pipeline.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/ppocr.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/providers.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/system.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/notification/windows_messenger.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ocr/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ocr/download_paddle_model.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/UI/ViewManagement/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/UI/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/Windows/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/delegate.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/export.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/idldsl.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/inspectable.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/roapi.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/types.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/rotypes/winstring.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/task/DiagnosisTask.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/task/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/task/exceptions.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/test/OKTestRunner.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/test/RunTests.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/test/TaskTestCase.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/third_party/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/third_party/paperclip.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/overlay/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/overlay/win32_gdi.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/Communicate.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/MainWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/MessageWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/StartController.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/TabTitles.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/HttpTextEdit.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/LinksBar.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/ProjectCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/UpdateCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/VersionCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/about/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/OKIcon.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/accent_color.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/config.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/design_system.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/icons.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/common/style_sheet.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/DebugTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/JobControls.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/OverlayWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/RunCodeTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/Screenshot.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/debug/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/events.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/GettextTranslator.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/path.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/i18n/update.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/overlay/OverlayWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/overlay/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/plugins/PluginTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/plugins/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/plugins/imported_tabs.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/card.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/discord.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/heart.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/message_window.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/setting_interface.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/status_bar.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/stop.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/dark/tab.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/card.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/discord.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/heart.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/message_window.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/setting_interface.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/status_bar.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/stop.svg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qss/light/tab.qss +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/qt.qrc +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/settings/GlobalConfigCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/settings/GlobalConfigTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/settings/SettingTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/settings/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/LogWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/SelectCaptureListView.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/SelectInteractionListView.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/StartCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/StartTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/start/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ConfigCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ConfigItemFactory.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ConfigLabelAndWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/EditTaskTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndButtons.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndDropDown.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndFileSelector.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndGlobal.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndList.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndMcpServer.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndMultiSelection.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndSpinBox.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndSwitchButton.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndTextEdit.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/LabelAndWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/MarkUpWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ModifyListDialog.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ModifyListItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/OneTimeTaskTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/PythonHighlighter.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/RecordScript.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ScheduleTaskTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/ScriptPackager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/StartButton.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TaskCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TaskManger.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TaskOpButton.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TaskTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TemplateFactory.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TemplateTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TooltipTableWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/TriggerTaskTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/tasks/schedule_index_sync.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/Alert.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/InitWorker.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/app.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/download.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/pip_util.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/pyappify_startup.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/touch_scroll.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/util/windows_thumbnail.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/BaseLoading.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/BaseWindow.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/Card.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/CustomTab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/EmptyCard.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/ExpandCardLayout.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/FlowLayout.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/FramelessDialog.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/ImageWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/ImportWarningDialog.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/ListTableWidgetItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/NumericTableWidgetItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/OkCompactSpinBox.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/SortingTableWidgetItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/StartLoadingDialog.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/StatusBar.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/Tab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/TabWidget.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/UpdateConfigWidgetItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/WidgetWithVLabel.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/YesNonWidgetItem.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/ui/qt/widget/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/update/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/update/copy_ok_folder.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/update/inline_ok_requirements.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/Analytics.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/GlobalConfig.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/__init__.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/blur.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/clazz.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/collection.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/color.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/config.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/explorer.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/file.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/gpu_driver_settings.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/handler.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/i18n.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/logger.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/partial_sync_repo.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/print_hwnd.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/process.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/version.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok/util/windows_schedule.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/entry_points.txt +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/not-zip-safe +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/requires.txt +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/ok_script.egg-info/top_level.txt +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/pyproject.toml +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/setup.cfg +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/setup.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_accent_color.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_app.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_base_interaction.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_blur.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_box.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_capture_update.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_cli.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_config_card.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_core_events.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_core_ui_services.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_debug_job_controls.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_device_manager.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_executor_jobs.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_expand_card_layout.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_explorer.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_global_config.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_gpu_driver_settings.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_handler.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_headless_imports.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_inline_ok_requirements.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_logger.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_main_window_notifications.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_main_window_startup_tab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_main_window_system_theme.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_mcp_server.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_mcp_setting.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_missing_frame.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_navigation_state.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_notifications.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_ok_mutex.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_overlay_custom_draw.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_overlay_lifecycle.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_package_metadata.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_plugin_staging.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_plugin_tabs.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_plugins.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_process.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_process_mutex.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_pyappify_startup_update.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_qt_events.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_qt_legacy_imports.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_qt_page_layout.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_runtime_startup.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_schedule_startup.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_schedule_task_index_sync.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_screenshot_naming.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_screenshot_rendering.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_start_controller.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_start_tab_overlay.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_task_executor_queue.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_task_reloading.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_task_ui.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_template_compression.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_template_generation.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_template_tab.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_touch_scroll.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_translation_fallback.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_ui_config.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_version.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_windows_graphics_capture.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_windows_graphics_hdr.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_windows_schedule_target_parse.py +0 -0
- {ok_script-2.0.18 → ok_script-2.0.20}/tests/test_windows_schedule_xml.py +0 -0
|
@@ -11,7 +11,15 @@ Do not use Computer Use skills, plugins, or tools for this workflow, including t
|
|
|
11
11
|
|
|
12
12
|
Read [docs/mcp.md](../../../docs/mcp.md) for the current server, tools, task contract, and artifacts. The coding agent already has local file and process access: write code and read logs/images directly. Use [setup-env](../setup-env/SKILL.md) or [setup-project](../setup-project/SKILL.md) only when setup is missing.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Before creating or changing named image features, read [generate-templates](../generate-templates/SKILL.md) and use the library's authoring/export pipeline:
|
|
15
|
+
|
|
16
|
+
1. Retain full original screenshots in `ok_templates/` and record feature rectangles and names in `ok_templates/coco_annotations.json` using `CocoTemplateStore`.
|
|
17
|
+
2. Call `ok.feature.FeatureSet.generate_templates` to export split PNGs into `assets/templates/` (or `ok_tasks/assets/templates/` for custom scripts). Let the exporter write the geometry-bearing filenames.
|
|
18
|
+
3. Configure `template_matching.template_folder` and use `find_feature`/`find_one` with the original feature names in task code.
|
|
19
|
+
|
|
20
|
+
Do not replace this pipeline with hand-cropped runtime PNGs, a custom template registry, or a parallel `cv2.matchTemplate` loader for named features. Crop previews are diagnostics, not runtime assets. Existing packed COCO assets and `coco_feature_json` remain supported. The split loader reports malformed filenames; fix the source annotation and regenerate instead of renaming crops or ignoring the error.
|
|
21
|
+
|
|
22
|
+
The full screenshots in `ok_templates/` can also serve directly as regression-test fixtures. Follow [write-test](../write-test/SKILL.md) to exercise real task recognition with `TaskTestCase.set_image()` or the exported assets with `FeatureSet`; there is no need to duplicate these images under `tests/images/`. A source-image self-match checks the export path; add independent positive and negative screenshots when available to check recognition robustness.
|
|
15
23
|
|
|
16
24
|
For existing registered tasks, prefer [reload-tasks](../reload-tasks/SKILL.md): discover their source with `list_tasks()`, edit it in place, call `reload_tasks(task_ids=[...])`, and wait for a successful reload before testing. Keep automation behavior in its existing module; use temporary MCP files only as thin validation harnesses. Create new task implementations when the requested functionality is new.
|
|
17
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-templates
|
|
3
|
-
description: Create
|
|
3
|
+
description: Create or change named image features using ok-script's ok_templates screenshots, COCO annotations, and split exporter; verify them with find_feature or find_one and reuse screenshots in tests.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Generate and use templates
|
|
@@ -15,6 +15,13 @@ split runtime assets. Keep source screenshots intact so both agents and the
|
|
|
15
15
|
Template tab can inspect and reannotate them. The old compression APIs and dialog
|
|
16
16
|
option are obsolete; use the split exporter for new or regenerated assets.
|
|
17
17
|
|
|
18
|
+
For new named features, do not write standalone runtime crops into `assets/`,
|
|
19
|
+
invent a template metadata format, or implement a separate `cv2.matchTemplate`
|
|
20
|
+
registry/loader. Use `CocoTemplateStore` for authoring, `generate_templates` for
|
|
21
|
+
runtime exports, and the library's named-feature matching APIs in tasks. A crop
|
|
22
|
+
preview may be written outside the export folder for inspection, but it does not
|
|
23
|
+
replace the source screenshot, COCO annotation, or generated split asset.
|
|
24
|
+
|
|
18
25
|
Run from the automation project's root using its interpreter, following
|
|
19
26
|
[use-venv](../use_venv/SKILL.md). For live capture and task execution follow
|
|
20
27
|
[develop](../develop/SKILL.md), including reset, baseline verification, and
|
|
@@ -172,6 +179,15 @@ prove recognition is robust. Use the project's actual threshold, preprocessing,
|
|
|
172
179
|
and anchor settings for representative verification. Keep evidence of what was
|
|
173
180
|
tested and what remains unverified.
|
|
174
181
|
|
|
182
|
+
Full screenshots in `ok_templates/` are also reusable offline test fixtures.
|
|
183
|
+
Pass their paths directly to `TaskTestCase.set_image()` to test the application's
|
|
184
|
+
real recognition methods, or load them as frames for `FeatureSet` tests using
|
|
185
|
+
the generated runtime assets. Keep referenced screenshots with the project so
|
|
186
|
+
tests remain reproducible; copying them to `tests/images/` is unnecessary.
|
|
187
|
+
Retain independent positive/negative captures when available, and assert the
|
|
188
|
+
expected state or match geometry rather than only checking that an image loads.
|
|
189
|
+
Follow [write-test](../write-test/SKILL.md) for harness setup and isolation.
|
|
190
|
+
|
|
175
191
|
In task code, use the existing methods:
|
|
176
192
|
|
|
177
193
|
```python
|
|
@@ -7,7 +7,7 @@ description: Install the ok-script Python package and create or repair a consumi
|
|
|
7
7
|
|
|
8
8
|
Work in the consuming application's directory and use its configured environment or `.venv`. Inspect its requirements, lockfile, supported Python versions, and installed packages before changing dependencies. Installing and using ok-script does not require a library source checkout.
|
|
9
9
|
|
|
10
|
-
Use this skill for requests such as "install ok-script and set up its environment", even before an MCP server exists. Read this file directly from the repository or installed package; starting MCP is not a prerequisite. After installation and verification,
|
|
10
|
+
Use this skill for requests such as "install ok-script and set up its environment", even before an MCP server exists. Read this file directly from the repository or installed package; starting MCP is not a prerequisite. After installation and verification, generate the local development skill before the project-creation handoff below.
|
|
11
11
|
|
|
12
12
|
## Interpreter and dependencies
|
|
13
13
|
|
|
@@ -39,6 +39,34 @@ If the application already has a launcher, run it with its environment to catch
|
|
|
39
39
|
|
|
40
40
|
Report the environment path, dependency profiles, OpenCV choice, and verification outcome.
|
|
41
41
|
|
|
42
|
+
## Generate the project-local development skill
|
|
43
|
+
|
|
44
|
+
After successful installation, create
|
|
45
|
+
`<cwd>/.agents/skills/ok-script-develop/SKILL.md` in the consuming workspace where
|
|
46
|
+
the user requested setup. This is part of agent setup, including installation-only
|
|
47
|
+
requests; it does not depend on accepting project creation or starting MCP. When
|
|
48
|
+
repairing an environment, add the skill if it is missing.
|
|
49
|
+
|
|
50
|
+
Use [the generic development skill template](assets/ok-script-develop/SKILL.md)
|
|
51
|
+
as the initial content. Prefer the template shipped with the selected installed
|
|
52
|
+
release; locate this `setup-env` skill through `ok.core.skills.list_skills()` and
|
|
53
|
+
resolve `assets/ok-script-develop/SKILL.md` from its parent directory. If the
|
|
54
|
+
installed release predates the template, use the template accompanying these
|
|
55
|
+
setup instructions without upgrading the dependency.
|
|
56
|
+
|
|
57
|
+
Create the destination directory as needed and write the template as UTF-8. If
|
|
58
|
+
the destination already exists, read it first and preserve its project-specific
|
|
59
|
+
guidance; merge missing discovery instructions only when needed. Do not replace
|
|
60
|
+
a customized skill with the generic template. Keep the template's generic name
|
|
61
|
+
and description for new skills; do not copy game-specific observations, fixed
|
|
62
|
+
machine paths, or unrelated application skills from another project.
|
|
63
|
+
|
|
64
|
+
The generated skill discovers the library's version-matched instructions in place;
|
|
65
|
+
do not copy the full consumer skill catalog into the application. Verify the
|
|
66
|
+
generated file has its `name` and `description` frontmatter, and that its discovery
|
|
67
|
+
instructions locate this environment's `develop/SKILL.md`. Report the generated
|
|
68
|
+
or reused skill's path with the environment results.
|
|
69
|
+
|
|
42
70
|
## Offer to create a project
|
|
43
71
|
|
|
44
72
|
After a successful initial installation, ask whether the user wants to create an automation project and which game or app it should target. For example: "ok-script is installed. Would you like to create an automation project now? If so, which game or app, and is it a Windows app or an Android device/emulator?" Wait for the answer before creating a project that has not already been requested.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ok-script-develop
|
|
3
|
+
description: Develop and debug an application's automation with ok-script, including tasks, configuration, recognition assets, and tests. Discover the selected library's consumer skills and apply the project's conventions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Develop with ok-script
|
|
7
|
+
|
|
8
|
+
Work in the consuming application's project and use its configured Python
|
|
9
|
+
environment. This skill provides discovery and project integration for any game
|
|
10
|
+
or app using ok-script; the selected library supplies the development workflow
|
|
11
|
+
and API contracts. Library maintenance is outside this skill's scope.
|
|
12
|
+
|
|
13
|
+
## Locate the library instructions
|
|
14
|
+
|
|
15
|
+
Before changing automation behavior, locate the consumer skills matching the
|
|
16
|
+
library this application actually uses:
|
|
17
|
+
|
|
18
|
+
1. Check the project's local `ok` directory or configured source link. Resolve
|
|
19
|
+
symlinks and junctions. A source checkout keeps skills at
|
|
20
|
+
`<resolved-ok>/../.agents/skills`; a packaged directory keeps them at
|
|
21
|
+
`<resolved-ok>/agent_resources/.agents/skills`.
|
|
22
|
+
2. If that source has no consumer skills, use the application's interpreter and
|
|
23
|
+
`importlib.metadata.distribution('ok-script').locate_file('ok')` to locate its
|
|
24
|
+
installed package, then check `agent_resources/.agents/skills` there. Do not
|
|
25
|
+
use another environment's global installation.
|
|
26
|
+
3. Read `develop/SKILL.md` in the selected skill directory. Resolve its links
|
|
27
|
+
relative to that original file, including the MCP guide and input references.
|
|
28
|
+
Read `reload-tasks` for registered tasks, `generate-templates` for visual
|
|
29
|
+
assets, and `write-test` for tests. Read setup skills when environment or
|
|
30
|
+
runtime setup is needed.
|
|
31
|
+
|
|
32
|
+
When available, the selected package's `core/skills.py` provides `list_skills()`
|
|
33
|
+
and `get_skill()` with absolute source paths. Load that file with
|
|
34
|
+
`runpy.run_path` to discover instructions without importing the GUI runtime.
|
|
35
|
+
For example, with a local `ok` directory, run this using the project interpreter
|
|
36
|
+
from the application root:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
import runpy
|
|
41
|
+
|
|
42
|
+
catalog = runpy.run_path(str(Path('ok').resolve() / 'core' / 'skills.py'))
|
|
43
|
+
for skill in catalog['list_skills']():
|
|
44
|
+
print(skill['id'], skill['path'])
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Keep the library's detailed instructions in their original location so they
|
|
48
|
+
follow its installed version. Inspect that version's source and signatures for
|
|
49
|
+
API details. If no consumer skills are available, report the missing resources
|
|
50
|
+
and use the project's setup guidance; do not invent MCP tools or silently upgrade
|
|
51
|
+
the dependency just to obtain instructions.
|
|
52
|
+
|
|
53
|
+
## Apply the workflow to this project
|
|
54
|
+
|
|
55
|
+
Follow the selected library's development skill for MCP startup, connection
|
|
56
|
+
discovery, task recovery, reloads, and runtime validation. Use ok-script APIs and
|
|
57
|
+
MCP for target capture and interaction. Do not use Computer Use skills, plugins,
|
|
58
|
+
or tools for this workflow.
|
|
59
|
+
|
|
60
|
+
Inspect the project's instructions, config, launchers, existing tasks, and local
|
|
61
|
+
skills before implementing changes. Reuse its task bases, registration style,
|
|
62
|
+
recovery helpers, assets, and localization conventions. Keep behavior in permanent
|
|
63
|
+
application modules and use thin MCP harnesses to exercise those implementations.
|
|
64
|
+
|
|
65
|
+
For new or changed named image features, read the library's `generate-templates`
|
|
66
|
+
skill before creating assets. Keep full screenshots in `ok_templates/`, annotate
|
|
67
|
+
them in `ok_templates/coco_annotations.json` with `CocoTemplateStore`, and call
|
|
68
|
+
`generate_templates` to produce split features in `assets/templates/` (or
|
|
69
|
+
`ok_tasks/assets/templates/` for custom scripts). Use the original names through
|
|
70
|
+
`find_feature`/`find_one`. Do not substitute hand-cropped runtime PNGs, a custom
|
|
71
|
+
template registry, or a separate `cv2.matchTemplate` loader for this pipeline.
|
|
72
|
+
|
|
73
|
+
The full images in `ok_templates/` can also be used directly as regression-test
|
|
74
|
+
fixtures with `TaskTestCase.set_image()` or `FeatureSet`. Read the library's
|
|
75
|
+
`write-test` skill, exercise real recognition with generated assets, and retain
|
|
76
|
+
independent positive/negative screenshots when available. The source-image
|
|
77
|
+
self-match alone verifies export consistency, not recognition robustness.
|
|
78
|
+
|
|
79
|
+
Use the configured project environment even when it is shared from a parent
|
|
80
|
+
workspace. Reuse this project's live runtime when suitable and follow the
|
|
81
|
+
library's process ownership rules when a restart is required. Validate observable
|
|
82
|
+
target behavior and relevant GUI lifecycle paths as described by the library.
|
|
83
|
+
If the target is unavailable, continue useful code and offline checks and report
|
|
84
|
+
the specific runtime checks that remain unverified.
|
|
@@ -43,6 +43,12 @@ workspace/
|
|
|
43
43
|
|
|
44
44
|
Create supporting directories as needed. Reuse a matching existing project folder; if the current directory is already that project's folder, edit it in place rather than nesting another copy. Keep separate projects' config and launch scripts separate, even when they target the same app.
|
|
45
45
|
|
|
46
|
+
Ensure each application's root has `.agents/skills/ok-script-develop/SKILL.md`,
|
|
47
|
+
following the local skill generation instructions in [setup-env](../setup-env/SKILL.md).
|
|
48
|
+
Do this even when its environment is shared with the parent workspace, so an agent
|
|
49
|
+
opened directly in the application folder can discover development guidance.
|
|
50
|
+
Preserve existing project-specific skill content.
|
|
51
|
+
|
|
46
52
|
Projects may share the workspace environment just installed when their dependencies are compatible, or use a project-local environment when required. Record the chosen interpreter and use its absolute path in shortcuts and run instructions. Target launchers must work when invoked by absolute path from another working directory: resolve paths from `__file__`, make the project's task modules and config importable, and set the working directory to that project's subfolder before starting the runtime. Resolve mutable paths under that same folder so projects do not share settings, logs, or MCP ownership accidentally.
|
|
47
53
|
|
|
48
54
|
Prefer the application's installed ok-script dependency. If the user explicitly requests a source link to an existing library installation, link `<project-root>\ok` to that checkout's `ok` directory and add the link's parent to `sys.path` before importing `ok`. Prefer a directory symbolic link; if Windows denies symlink privileges, use a directory junction. Verify existing destinations and resolved paths before replacing anything; never recursively delete through the link. This is dependency access, not permission to modify library code.
|
|
@@ -27,7 +27,7 @@ Import `TaskTestCase` from `ok.test.TaskTestCase`; set class attributes `task_cl
|
|
|
27
27
|
|
|
28
28
|
The current harness initializes one task per test class, replaces capture with `ImageCaptureMethod`, and uses `DoNothingInteraction`. `set_image(path)` advances the frame and checks template sizing; `set_images(*paths)` installs a sequence and advances its first frame. Read the capture implementation when testing frame progression rather than assuming repeated reads advance it.
|
|
29
29
|
|
|
30
|
-
-
|
|
30
|
+
- Reuse full source screenshots in the target project's `ok_templates/` directly as test fixtures, including screenshots used to author COCO annotations and split features. Pass their paths to `set_image()`; no copy into `tests/images/` is required. Keep referenced images with the project and confirm they exist and load. Additional test-only captures may live under `tests/images/` or the project's existing fixture directory.
|
|
31
31
|
- Load the image before calling the recognition method. Exercise real recognition rather than mocking the method being tested.
|
|
32
32
|
- Assert the detected state, value, feature name, confidence, or box geometry as appropriate. Include an absent or negative case when it distinguishes the regression.
|
|
33
33
|
- For scaling bugs, use representative resolutions and aspect ratios with `subTest`; preserve the intended center/right anchors and allow a justified pixel tolerance. Include positive matches and blank-frame negatives when relevant.
|
|
@@ -35,6 +35,15 @@ The current harness initializes one task per test class, replaces capture with `
|
|
|
35
35
|
- Do not treat no-op input as proof that an in-game click worked. Test action intent with mocks; use the [develop skill](../develop/SKILL.md) when actual GUI/MCP interaction is part of the request.
|
|
36
36
|
- For fixture annotation or named feature creation, follow [generate-templates](../generate-templates/SKILL.md).
|
|
37
37
|
|
|
38
|
+
For example, in a `TaskTestCase` method, call
|
|
39
|
+
`self.set_image(str(project_root / "ok_templates" / "settings-open.png"))`, then
|
|
40
|
+
invoke the real task recognition method and assert its result. Resolve
|
|
41
|
+
`project_root` from the test file or the project's existing test configuration.
|
|
42
|
+
Use the generated `assets/templates` features through the real application
|
|
43
|
+
config. Matching a feature against its own authoring screenshot verifies the
|
|
44
|
+
annotation/export/load path; include independent positives and negatives when
|
|
45
|
+
available to catch false matches and appearance changes.
|
|
46
|
+
|
|
38
47
|
For direct split-template tests, construct `FeatureSet(False, None, 0.002, 0.002,
|
|
39
48
|
template_folder=<absolute export folder>)`. For packed COCO tests, pass the JSON
|
|
40
49
|
path as the second argument. Match using the original feature name, without the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ok-script
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.20
|
|
4
4
|
Summary: Automation with Computer Vision for Python
|
|
5
5
|
Author-email: ok-oldking <firedcto@gmail.com>
|
|
6
6
|
License: ok-script License
|
|
@@ -212,6 +212,8 @@ python -m venv .venv
|
|
|
212
212
|
- [白荆回廊](https://github.com/ok-oldking/ok-baijing)(停止维护)
|
|
213
213
|
- [明日方舟:终末地](https://github.com/AliceJump/ok-end-field)
|
|
214
214
|
- [异环](https://github.com/BnanZ0/ok-nte)
|
|
215
|
+
- [棕色尘埃 2](https://github.com/GodRaymond233/ok-bd2)
|
|
216
|
+
- [蓝色星原:旅谣](https://github.com/longer-sausage/OK-AzurPromilia)
|
|
215
217
|
|
|
216
218
|
## 社区与发布
|
|
217
219
|
|
|
@@ -85,6 +85,8 @@ python -m venv .venv
|
|
|
85
85
|
- [白荆回廊](https://github.com/ok-oldking/ok-baijing)(停止维护)
|
|
86
86
|
- [明日方舟:终末地](https://github.com/AliceJump/ok-end-field)
|
|
87
87
|
- [异环](https://github.com/BnanZ0/ok-nte)
|
|
88
|
+
- [棕色尘埃 2](https://github.com/GodRaymond233/ok-bd2)
|
|
89
|
+
- [蓝色星原:旅谣](https://github.com/longer-sausage/OK-AzurPromilia)
|
|
88
90
|
|
|
89
91
|
## 社区与发布
|
|
90
92
|
|
|
@@ -21,14 +21,18 @@ When asked to install, configure, or repair ok-script or its Python environment,
|
|
|
21
21
|
read https://raw.githubusercontent.com/ok-oldking/ok-script/master/docs/agent-setup.md
|
|
22
22
|
and follow the relevant setup skills before changing the environment.
|
|
23
23
|
Use this project's virtual environment and preserve its dependency constraints.
|
|
24
|
+
After installation, generate .agents/skills/ok-script-develop/SKILL.md in the
|
|
25
|
+
current workspace using the setup-env template, preserving any existing custom skill.
|
|
24
26
|
After installation, offer to create an automation project and ask for missing
|
|
25
27
|
game/app details. Give each project its own subfolder, config, and start scripts.
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
Installing a Python package does not register its instructions with a coding
|
|
29
31
|
agent. The prompt or project instruction supplies the discovery link; after
|
|
30
|
-
installation, the package also provides local copies of the skills.
|
|
31
|
-
|
|
32
|
+
installation, the package also provides local copies of the skills. The coding
|
|
33
|
+
agent then generates a discoverable development skill in the consuming workspace;
|
|
34
|
+
`pip install` alone does not write project instructions. No MCP server is needed
|
|
35
|
+
to read the setup instructions or generate this local skill.
|
|
32
36
|
|
|
33
37
|
## Instructions for the coding agent
|
|
34
38
|
|
|
@@ -49,26 +53,36 @@ server is needed to read the setup instructions.
|
|
|
49
53
|
workflow. Select only the profiles the requested application needs; a desktop
|
|
50
54
|
GUI commonly uses `default,qt`, with exactly one compatible OpenCV variant
|
|
51
55
|
installed separately. Verify the environment before offering project creation.
|
|
52
|
-
4. After
|
|
56
|
+
4. After installation, generate
|
|
57
|
+
`<cwd>/.agents/skills/ok-script-develop/SKILL.md` using the generic template
|
|
58
|
+
linked from `setup-env`. This step also applies to installation-only requests;
|
|
59
|
+
preserve and merge an existing customized skill rather than overwriting it.
|
|
60
|
+
Verify it can locate the selected library's consumer development instructions.
|
|
61
|
+
The skill applies to any consuming game or app and discovers the library's
|
|
62
|
+
instructions in place instead of duplicating them.
|
|
63
|
+
5. After a successful initial installation, ask: "Would you like to create an
|
|
53
64
|
automation project now? Which game or app should it automate, and is it a
|
|
54
65
|
Windows app or an Android device/emulator?" If the user already requested a
|
|
55
66
|
project, ask only for missing details. Skip this offer when repairing an
|
|
56
67
|
existing project or when the user has explicitly declined project creation.
|
|
57
|
-
|
|
68
|
+
6. When project creation is requested, read the
|
|
58
69
|
[setup-project skill](https://github.com/ok-oldking/ok-script/blob/master/.agents/skills/setup-project/SKILL.md).
|
|
59
70
|
Identify the actual executable/window or device/app from the user's answers
|
|
60
71
|
and local inspection. Ask for any required details that remain ambiguous;
|
|
61
72
|
wait for those answers before writing target-dependent config. Create each
|
|
62
73
|
project in its own named workspace subfolder, containing its own `config.py`,
|
|
63
74
|
`start_gui.py`, and `start_mcp.py`. Keep its tasks, assets, settings, and logs
|
|
64
|
-
in that folder too.
|
|
75
|
+
in that folder too. Ensure its root also has the local `ok-script-develop`
|
|
76
|
+
skill, even if it shares the workspace environment. Omit `gui_icon` to use the
|
|
77
|
+
default `OK` PNG bundled with
|
|
65
78
|
the Python package; set it only when supplying a custom application icon.
|
|
66
79
|
Reuse an existing project in place. Projects may share
|
|
67
80
|
the prepared environment when compatible. Use the installed version's APIs
|
|
68
81
|
and verify that launchers work when invoked from outside their subfolder.
|
|
69
|
-
|
|
82
|
+
7. Run the checks in the relevant skills. Report the environment path, installed
|
|
70
83
|
ok-script version, dependency profiles, OpenCV choice, and verification
|
|
71
|
-
results
|
|
84
|
+
results, plus the generated or reused development skill path. For application
|
|
85
|
+
setup, also report the project folder, config,
|
|
72
86
|
launcher paths, and which target capture/input checks succeeded.
|
|
73
87
|
|
|
74
88
|
## Read skills from an installed package
|
|
@@ -14,6 +14,11 @@ Use Split for new exports. Existing COCO assets remain readable.
|
|
|
14
14
|
Keep the original screenshots and COCO annotations in `ok_templates` for editing
|
|
15
15
|
and future exports. Split exports require only the PNG files at runtime.
|
|
16
16
|
|
|
17
|
+
Coding agents should use this same pipeline: author with `CocoTemplateStore`,
|
|
18
|
+
export with `generate_templates`, and match named features with
|
|
19
|
+
`find_feature`/`find_one`. Hand-cropped runtime PNGs and a custom OpenCV template
|
|
20
|
+
loader bypass the library's annotation, scaling, and export workflow.
|
|
21
|
+
|
|
17
22
|
## Configuration
|
|
18
23
|
|
|
19
24
|
Add `template_folder` alongside the existing configuration; all variance,
|
|
@@ -106,6 +111,14 @@ boxes = features.find_feature(frame, 'settings_save', threshold=0.95)
|
|
|
106
111
|
assert len(boxes) == 1, boxes
|
|
107
112
|
```
|
|
108
113
|
|
|
114
|
+
Full screenshots in `ok_templates` can also serve directly as regression-test
|
|
115
|
+
fixtures. Pass a screenshot path to `TaskTestCase.set_image()` to exercise the
|
|
116
|
+
application's real recognition methods, or load it for a `FeatureSet` test as
|
|
117
|
+
above. Keep referenced screenshots with the project; no duplicate under
|
|
118
|
+
`tests/images` is needed. A self-match on the authoring image verifies the export
|
|
119
|
+
path. Add independent positive and negative screenshots when available to test
|
|
120
|
+
recognition robustness, using the application's actual matching settings.
|
|
121
|
+
|
|
109
122
|
Also verify representative screenshots at the supported resolutions. The GUI
|
|
110
123
|
Save action reloads its feature set. After programmatic export, refresh cached
|
|
111
124
|
features with `feature_set.process_data()` on the executor thread, or restart the
|
|
@@ -12,6 +12,13 @@ The agent writes and edits project files, starts the local runtime, and reads lo
|
|
|
12
12
|
|
|
13
13
|
MCP supplies skills and task execution, not a Python API catalog or `get_api` tool. Use the application's interpreter and inspect its installed package for exact signatures, docstrings, inherited methods, and return behavior. No library checkout is needed. See [agent prompts](en/agent-prompts.md) for API-only discovery and existing-task repair examples.
|
|
14
14
|
|
|
15
|
+
The server's connection instructions direct agents to `get_skill("generate-templates")`
|
|
16
|
+
before creating named image features: keep full screenshots and COCO annotations
|
|
17
|
+
in `ok_templates`, export split features with `generate_templates`, and use
|
|
18
|
+
`find_feature`/`find_one` in tasks. Those full screenshots can also be used directly
|
|
19
|
+
as regression-test fixtures; `get_skill("write-test")` describes the test workflow.
|
|
20
|
+
These instructions and skills come from the server's installed ok-script version.
|
|
21
|
+
|
|
15
22
|
## Install and start
|
|
16
23
|
|
|
17
24
|
If the project has no environment or MCP runtime yet, start with the
|
|
@@ -203,12 +203,13 @@ def retry(func):
|
|
|
203
203
|
|
|
204
204
|
|
|
205
205
|
class NemuIpcImpl:
|
|
206
|
-
def __init__(self, nemu_folder: str, instance_id: int, display_id: int = 0):
|
|
206
|
+
def __init__(self, nemu_folder: str, instance_id: int, display_id: int = 0, runtime_version: str = '12.0'):
|
|
207
207
|
"""
|
|
208
208
|
Args:
|
|
209
209
|
nemu_folder: Installation path of MuMu12, e.g. E:/ProgramFiles/MuMuPlayer-12.0
|
|
210
210
|
instance_id: Emulator instance ID, starting from 0
|
|
211
211
|
display_id: Always 0 if keep app alive was disabled
|
|
212
|
+
runtime_version: Selected instance's runtime directory, such as 12.0 or 15.0
|
|
212
213
|
"""
|
|
213
214
|
self.nemu_folder: str = nemu_folder
|
|
214
215
|
self.instance_id: int = instance_id
|
|
@@ -218,8 +219,8 @@ class NemuIpcImpl:
|
|
|
218
219
|
list_dll = [
|
|
219
220
|
# MuMuPlayer12
|
|
220
221
|
os.path.abspath(os.path.join(nemu_folder, './shell/sdk/external_renderer_ipc.dll')),
|
|
221
|
-
#
|
|
222
|
-
os.path.abspath(os.path.join(nemu_folder, '
|
|
222
|
+
# MuMu's versioned runtime layout
|
|
223
|
+
os.path.abspath(os.path.join(nemu_folder, 'nx_device', runtime_version, 'shell/sdk/external_renderer_ipc.dll')),
|
|
223
224
|
]
|
|
224
225
|
self.lib = None
|
|
225
226
|
for ipc_dll in list_dll:
|
|
@@ -460,11 +461,12 @@ class NemuIpcImpl:
|
|
|
460
461
|
class NemuIpc:
|
|
461
462
|
_screenshot_interval = Timer(0.1)
|
|
462
463
|
|
|
463
|
-
def __init__(self, nemu_folder: str, instance_id: int, display_id: int = 0):
|
|
464
|
+
def __init__(self, nemu_folder: str, instance_id: int, display_id: int = 0, runtime_version: str = '12.0'):
|
|
464
465
|
self.nemu_ipc = None
|
|
465
466
|
self.nemu_folder = nemu_folder
|
|
466
467
|
self.instance_id = instance_id
|
|
467
468
|
self.display_id = display_id
|
|
469
|
+
self.runtime_version = runtime_version
|
|
468
470
|
self.nemu_ipc = self.init_nemu_ipc()
|
|
469
471
|
|
|
470
472
|
def init_nemu_ipc(self) -> NemuIpcImpl:
|
|
@@ -481,7 +483,8 @@ class NemuIpc:
|
|
|
481
483
|
return NemuIpcImpl(
|
|
482
484
|
nemu_folder=self.nemu_folder,
|
|
483
485
|
instance_id=self.instance_id,
|
|
484
|
-
display_id=
|
|
486
|
+
display_id=self.display_id,
|
|
487
|
+
runtime_version=self.runtime_version
|
|
485
488
|
).__enter__()
|
|
486
489
|
except (NemuIpcIncompatible, NemuIpcError, JobTimeout) as e:
|
|
487
490
|
logger.error('Unable to initialize NemuIpc', e)
|
|
@@ -113,6 +113,14 @@ def create_mcp_app(runner, token, port, request_exit=None):
|
|
|
113
113
|
'with the relevant skill ID before working. Skills are also MCP resources. '
|
|
114
114
|
'These skills are for the consuming application: its tasks, config, assets, '
|
|
115
115
|
'environment and tests, not for developing or publishing the ok-script library. '
|
|
116
|
+
'Before creating or changing named image features, read get_skill("generate-templates"). '
|
|
117
|
+
'Keep full screenshots and coco_annotations.json in ok_templates, author with '
|
|
118
|
+
'CocoTemplateStore, and call generate_templates to export split features into '
|
|
119
|
+
'assets/templates (ok_tasks/assets/templates for custom scripts). Use find_feature '
|
|
120
|
+
'or find_one with original feature names; do not substitute hand-cropped runtime '
|
|
121
|
+
'PNGs or a custom cv2.matchTemplate loader. Full ok_templates screenshots can also '
|
|
122
|
+
'be used directly as regression-test fixtures with TaskTestCase.set_image or '
|
|
123
|
+
'FeatureSet; read get_skill("write-test") for testing. '
|
|
116
124
|
'For existing tasks, prefer list_tasks, edit the returned source files in place, '
|
|
117
125
|
'then reload_tasks with task_ids (omit task_ids to reload all). Poll get_run_status '
|
|
118
126
|
'until the reload finishes before testing. Read the reload-tasks skill for this workflow. '
|
|
@@ -36,8 +36,8 @@ class BaseCaptureMethod:
|
|
|
36
36
|
"""Capture a frame.
|
|
37
37
|
|
|
38
38
|
:param busy_wait: Seconds to wait when another caller owns the capture.
|
|
39
|
-
The default 0 returns None immediately
|
|
40
|
-
|
|
39
|
+
The default 0 returns None immediately. The task executor waits
|
|
40
|
+
briefly; one-off captures should wait longer.
|
|
41
41
|
"""
|
|
42
42
|
if self.exit_event.is_set():
|
|
43
43
|
return
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
import re
|
|
3
4
|
|
|
4
5
|
from ok.util.collection import deep_get
|
|
5
6
|
from ok.util.logger import Logger
|
|
@@ -10,7 +11,7 @@ logger = Logger.get_logger(__name__)
|
|
|
10
11
|
|
|
11
12
|
class NemuIpcCaptureMethod(BaseCaptureMethod):
|
|
12
13
|
name = "Nemu Ipc Capture"
|
|
13
|
-
description = "
|
|
14
|
+
description = "MuMu Player native capture"
|
|
14
15
|
|
|
15
16
|
def __init__(self, device_manager, exit_event, width=0, height=0):
|
|
16
17
|
super().__init__()
|
|
@@ -34,16 +35,22 @@ class NemuIpcCaptureMethod(BaseCaptureMethod):
|
|
|
34
35
|
self.nemu_impl = NemuIpc(
|
|
35
36
|
nemu_folder=self.base_folder(),
|
|
36
37
|
instance_id=self.emulator.player_id,
|
|
37
|
-
display_id=0
|
|
38
|
+
display_id=0,
|
|
39
|
+
runtime_version=self.runtime_version()
|
|
38
40
|
)
|
|
39
41
|
|
|
40
42
|
def base_folder(self):
|
|
41
43
|
return os.path.dirname(os.path.dirname(self.emulator.path))
|
|
42
44
|
|
|
45
|
+
def runtime_version(self):
|
|
46
|
+
match = re.search(r'-(\d+(?:\.\d+)+)-\d+$', getattr(self.emulator, 'name', ''))
|
|
47
|
+
return match.group(1) if match else '12.0'
|
|
48
|
+
|
|
43
49
|
def check_mumu_app_keep_alive_400(self):
|
|
50
|
+
instance_name = getattr(self.emulator, 'name', None) or f'MuMuPlayer-12.0-{self.emulator.player_id}'
|
|
44
51
|
file = os.path.abspath(os.path.join(
|
|
45
52
|
self.base_folder(),
|
|
46
|
-
|
|
53
|
+
'vms', instance_name, 'configs/customer_config.json'))
|
|
47
54
|
|
|
48
55
|
try:
|
|
49
56
|
with open(file, mode='r', encoding='utf-8') as f:
|
|
@@ -151,3 +151,33 @@ ADB_KEY_MAP = {
|
|
|
151
151
|
'printscreen': 'KEYCODE_SYSRQ',
|
|
152
152
|
'print_screen': 'KEYCODE_SYSRQ',
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
XBUTTON1 = 0x0001
|
|
156
|
+
XBUTTON2 = 0x0002
|
|
157
|
+
MOUSEEVENTF_XDOWN = 0x0080
|
|
158
|
+
MOUSEEVENTF_XUP = 0x0100
|
|
159
|
+
|
|
160
|
+
WM_XBUTTONDOWN = 0x020B
|
|
161
|
+
WM_XBUTTONUP = 0x020C
|
|
162
|
+
MK_XBUTTON1 = 0x0020
|
|
163
|
+
MK_XBUTTON2 = 0x0040
|
|
164
|
+
|
|
165
|
+
MOUSE_BUTTON_MAP = {
|
|
166
|
+
'mouse4': XBUTTON1,
|
|
167
|
+
'xbutton1': XBUTTON1,
|
|
168
|
+
'mouse5': XBUTTON2,
|
|
169
|
+
'xbutton2': XBUTTON2,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def is_mouse_button(key) -> bool:
|
|
174
|
+
if not isinstance(key, str):
|
|
175
|
+
return False
|
|
176
|
+
return key.strip().lower() in MOUSE_BUTTON_MAP
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def get_mouse_button(key) -> int:
|
|
180
|
+
if not isinstance(key, str):
|
|
181
|
+
return 0
|
|
182
|
+
return MOUSE_BUTTON_MAP.get(key.strip().lower(), 0)
|
|
183
|
+
|
|
@@ -6,7 +6,10 @@ import win32gui
|
|
|
6
6
|
|
|
7
7
|
from ok.device.capture_methods.base import BaseCaptureMethod
|
|
8
8
|
from ok.device.interaction_methods.base import BaseInteraction
|
|
9
|
-
from ok.device.interaction_methods.keys import
|
|
9
|
+
from ok.device.interaction_methods.keys import (
|
|
10
|
+
vk_key_dict, is_mouse_button, get_mouse_button,
|
|
11
|
+
XBUTTON1, MK_XBUTTON1, MK_XBUTTON2, WM_XBUTTONDOWN, WM_XBUTTONUP
|
|
12
|
+
)
|
|
10
13
|
from ok.util.logger import Logger
|
|
11
14
|
|
|
12
15
|
logger = Logger.get_logger(__name__)
|
|
@@ -37,12 +40,27 @@ class PostMessageInteraction(BaseInteraction):
|
|
|
37
40
|
def send_key_down(self, key, activate=True):
|
|
38
41
|
if activate:
|
|
39
42
|
self.try_activate()
|
|
43
|
+
if is_mouse_button(key):
|
|
44
|
+
btn = get_mouse_button(key)
|
|
45
|
+
mk = MK_XBUTTON1 if btn == XBUTTON1 else MK_XBUTTON2
|
|
46
|
+
wparam = win32api.MAKELONG(mk, btn)
|
|
47
|
+
pos = getattr(self, 'mouse_pos', (0, 0))
|
|
48
|
+
lparam = win32api.MAKELONG(int(pos[0]), int(pos[1]))
|
|
49
|
+
self.post(WM_XBUTTONDOWN, wparam, lparam)
|
|
50
|
+
return
|
|
40
51
|
vk_code = self.get_key_by_str(key)
|
|
41
52
|
lparam = self.make_lparam(vk_code, is_up=False)
|
|
42
53
|
self.post(win32con.WM_KEYDOWN, vk_code, lparam)
|
|
43
54
|
|
|
44
55
|
def send_key_up(self, key):
|
|
45
56
|
# logger.debug(f'send_key_up {key}')
|
|
57
|
+
if is_mouse_button(key):
|
|
58
|
+
btn = get_mouse_button(key)
|
|
59
|
+
wparam = win32api.MAKELONG(0, btn)
|
|
60
|
+
pos = getattr(self, 'mouse_pos', (0, 0))
|
|
61
|
+
lparam = win32api.MAKELONG(int(pos[0]), int(pos[1]))
|
|
62
|
+
self.post(WM_XBUTTONUP, wparam, lparam)
|
|
63
|
+
return
|
|
46
64
|
vk_code = self.get_key_by_str(key)
|
|
47
65
|
lparam = self.make_lparam(vk_code, is_up=True)
|
|
48
66
|
self.post(win32con.WM_KEYUP, vk_code, lparam)
|
|
@@ -215,6 +233,9 @@ class PostMessageInteraction(BaseInteraction):
|
|
|
215
233
|
self._dynamic_target_hwnd = target_hwnd
|
|
216
234
|
|
|
217
235
|
local_x, local_y = win32gui.ScreenToClient(target_hwnd, (abs_x, abs_y))
|
|
236
|
+
# Button messages must use the same target-client coordinates as
|
|
237
|
+
# the preceding move, including when a child window is selected.
|
|
238
|
+
self.mouse_pos = (local_x, local_y)
|
|
218
239
|
|
|
219
240
|
hwnd_descriptions = []
|
|
220
241
|
for index, hwnd_info in enumerate(hwnds):
|
|
@@ -233,7 +254,8 @@ class PostMessageInteraction(BaseInteraction):
|
|
|
233
254
|
except Exception as e:
|
|
234
255
|
logger.error(f'update_mouse_pos conversion error targeting {base_hwnd}', e)
|
|
235
256
|
self._dynamic_target_hwnd = base_hwnd
|
|
236
|
-
|
|
257
|
+
self.mouse_pos = (int(x), int(y))
|
|
258
|
+
return win32api.MAKELONG(*self.mouse_pos)
|
|
237
259
|
|
|
238
260
|
def mouse_up(self, key="left"):
|
|
239
261
|
if key == "left":
|