ok-script 2.0.18__tar.gz → 2.0.19__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.
Files changed (396) hide show
  1. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/develop/SKILL.md +9 -1
  2. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/generate-templates/SKILL.md +17 -1
  3. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/setup-env/SKILL.md +29 -1
  4. ok_script-2.0.19/.agents/skills/setup-env/assets/ok-script-develop/SKILL.md +84 -0
  5. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/setup-project/SKILL.md +6 -0
  6. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/write-test/SKILL.md +10 -1
  7. {ok_script-2.0.18 → ok_script-2.0.19}/PKG-INFO +1 -1
  8. {ok_script-2.0.18 → ok_script-2.0.19}/docs/agent-setup.md +21 -7
  9. {ok_script-2.0.18 → ok_script-2.0.19}/docs/feature-crops.md +13 -0
  10. {ok_script-2.0.18 → ok_script-2.0.19}/docs/mcp.md +7 -0
  11. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/nemu_ipc.py +8 -5
  12. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/mcp_server.py +8 -0
  13. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/nemu_ipc.py +10 -3
  14. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/window.py +4 -0
  15. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/PKG-INFO +1 -1
  16. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/SOURCES.txt +1 -0
  17. ok_script-2.0.19/tests/test_nemu_ipc_capture.py +84 -0
  18. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_skills.py +2 -0
  19. ok_script-2.0.18/tests/test_nemu_ipc_capture.py +0 -40
  20. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/develop/agents/openai.yaml +0 -0
  21. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/develop/references/windows-input.md +0 -0
  22. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/reload-tasks/SKILL.md +0 -0
  23. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/reload-tasks/agents/openai.yaml +0 -0
  24. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/setup-env/agents/openai.yaml +0 -0
  25. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/setup-project/agents/openai.yaml +0 -0
  26. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/use_venv/SKILL.md +0 -0
  27. {ok_script-2.0.18 → ok_script-2.0.19}/.agents/skills/write-test/agents/openai.yaml +0 -0
  28. {ok_script-2.0.18 → ok_script-2.0.19}/LICENSE.txt +0 -0
  29. {ok_script-2.0.18 → ok_script-2.0.19}/MANIFEST.in +0 -0
  30. {ok_script-2.0.18 → ok_script-2.0.19}/README.md +0 -0
  31. {ok_script-2.0.18 → ok_script-2.0.19}/diagnostics/qq_trace.py +0 -0
  32. {ok_script-2.0.18 → ok_script-2.0.19}/examples/mcp_observe.py +0 -0
  33. {ok_script-2.0.18 → ok_script-2.0.19}/ok/__init__.py +0 -0
  34. {ok_script-2.0.18 → ok_script-2.0.19}/ok/__main__.py +0 -0
  35. {ok_script-2.0.18 → ok_script-2.0.19}/ok/alas/__init__.py +0 -0
  36. {ok_script-2.0.18 → ok_script-2.0.19}/ok/alas/emulator_base.py +0 -0
  37. {ok_script-2.0.18 → ok_script-2.0.19}/ok/alas/emulator_windows.py +0 -0
  38. {ok_script-2.0.18 → ok_script-2.0.19}/ok/alas/platform_windows.py +0 -0
  39. {ok_script-2.0.18 → ok_script-2.0.19}/ok/alas/utils.py +0 -0
  40. {ok_script-2.0.18 → ok_script-2.0.19}/ok/assets/default-icon.png +0 -0
  41. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/__init__.py +0 -0
  42. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/__init__.py +0 -0
  43. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/deep.py +0 -0
  44. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/minitouch.py +0 -0
  45. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/nemu_utils.py +0 -0
  46. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/pool.py +0 -0
  47. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/timer.py +0 -0
  48. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/adb/util.py +0 -0
  49. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/windows/__init__.py +0 -0
  50. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/windows/d3d11.py +0 -0
  51. {ok_script-2.0.18 → ok_script-2.0.19}/ok/capture/windows/dump.py +0 -0
  52. {ok_script-2.0.18 → ok_script-2.0.19}/ok/cli.py +0 -0
  53. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/__init__.py +0 -0
  54. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/capture_labels.py +0 -0
  55. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/code_runner.py +0 -0
  56. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/config_schema.py +0 -0
  57. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/downloads.py +0 -0
  58. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/events.py +0 -0
  59. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/icons.py +0 -0
  60. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/mcp_runner.py +0 -0
  61. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/notifications.py +0 -0
  62. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/plugin_staging.py +0 -0
  63. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/plugins.py +0 -0
  64. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/screenshot.py +0 -0
  65. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/script_editing.py +0 -0
  66. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/script_packager.py +0 -0
  67. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/script_templates.py +0 -0
  68. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/skills.py +0 -0
  69. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/start_controller.py +0 -0
  70. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/task_manager.py +0 -0
  71. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/template_store.py +0 -0
  72. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/translation.py +0 -0
  73. {ok_script-2.0.18 → ok_script-2.0.19}/ok/core/ui_config.py +0 -0
  74. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/DeviceManager.py +0 -0
  75. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/__init__.py +0 -0
  76. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture.py +0 -0
  77. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/__init__.py +0 -0
  78. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/adb.py +0 -0
  79. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/base.py +0 -0
  80. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/bitblt.py +0 -0
  81. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/bitblt_utils.py +0 -0
  82. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/browser.py +0 -0
  83. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/desktop_duplication.py +0 -0
  84. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/hwnd_window.py +0 -0
  85. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/image.py +0 -0
  86. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/types.py +0 -0
  87. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/update.py +0 -0
  88. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/windows_graphics.py +0 -0
  89. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/capture_methods/windows_graphics_hdr.py +0 -0
  90. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction.py +0 -0
  91. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/__init__.py +0 -0
  92. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/adb.py +0 -0
  93. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/base.py +0 -0
  94. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/browser.py +0 -0
  95. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/do_nothing.py +0 -0
  96. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/foreground_post_message.py +0 -0
  97. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/genshin.py +0 -0
  98. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/keys.py +0 -0
  99. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/post_message.py +0 -0
  100. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/pydirect.py +0 -0
  101. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/pynput.py +0 -0
  102. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/interaction_methods/swipe.py +0 -0
  103. {ok_script-2.0.18 → ok_script-2.0.19}/ok/device/intercation.py +0 -0
  104. {ok_script-2.0.18 → ok_script-2.0.19}/ok/feature/Box.py +0 -0
  105. {ok_script-2.0.18 → ok_script-2.0.19}/ok/feature/Feature.py +0 -0
  106. {ok_script-2.0.18 → ok_script-2.0.19}/ok/feature/FeatureSet.py +0 -0
  107. {ok_script-2.0.18 → ok_script-2.0.19}/ok/feature/__init__.py +0 -0
  108. {ok_script-2.0.18 → ok_script-2.0.19}/ok/gui/__init__.py +0 -0
  109. {ok_script-2.0.18 → ok_script-2.0.19}/ok/gui/util/pyappify_startup.py +0 -0
  110. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/__init__.py +0 -0
  111. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/manager.py +0 -0
  112. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/messenger_images.py +0 -0
  113. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/pipeline.py +0 -0
  114. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/ppocr.py +0 -0
  115. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/providers.py +0 -0
  116. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/system.py +0 -0
  117. {ok_script-2.0.18 → ok_script-2.0.19}/ok/notification/windows_messenger.py +0 -0
  118. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ocr/__init__.py +0 -0
  119. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ocr/download_paddle_model.py +0 -0
  120. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  121. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  122. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  123. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  124. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  125. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  126. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  127. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  128. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  129. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Media/__init__.py +0 -0
  130. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  131. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Security/__init__.py +0 -0
  132. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  133. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  134. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/UI/ViewManagement/__init__.py +0 -0
  135. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/UI/__init__.py +0 -0
  136. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/Windows/__init__.py +0 -0
  137. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/__init__.py +0 -0
  138. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/delegate.py +0 -0
  139. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/export.py +0 -0
  140. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/idldsl.py +0 -0
  141. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/inspectable.py +0 -0
  142. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/roapi.py +0 -0
  143. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/types.py +0 -0
  144. {ok_script-2.0.18 → ok_script-2.0.19}/ok/rotypes/winstring.py +0 -0
  145. {ok_script-2.0.18 → ok_script-2.0.19}/ok/task/DiagnosisTask.py +0 -0
  146. {ok_script-2.0.18 → ok_script-2.0.19}/ok/task/TaskExecutor.py +0 -0
  147. {ok_script-2.0.18 → ok_script-2.0.19}/ok/task/__init__.py +0 -0
  148. {ok_script-2.0.18 → ok_script-2.0.19}/ok/task/exceptions.py +0 -0
  149. {ok_script-2.0.18 → ok_script-2.0.19}/ok/task/task.py +0 -0
  150. {ok_script-2.0.18 → ok_script-2.0.19}/ok/test/OKTestRunner.py +0 -0
  151. {ok_script-2.0.18 → ok_script-2.0.19}/ok/test/RunTests.py +0 -0
  152. {ok_script-2.0.18 → ok_script-2.0.19}/ok/test/TaskTestCase.py +0 -0
  153. {ok_script-2.0.18 → ok_script-2.0.19}/ok/test/__init__.py +0 -0
  154. {ok_script-2.0.18 → ok_script-2.0.19}/ok/third_party/__init__.py +0 -0
  155. {ok_script-2.0.18 → ok_script-2.0.19}/ok/third_party/paperclip.py +0 -0
  156. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/__init__.py +0 -0
  157. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/overlay/__init__.py +0 -0
  158. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/overlay/win32_gdi.py +0 -0
  159. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/Communicate.py +0 -0
  160. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/MainWindow.py +0 -0
  161. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/MessageWindow.py +0 -0
  162. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/StartController.py +0 -0
  163. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/TabTitles.py +0 -0
  164. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/__init__.py +0 -0
  165. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/AboutTab.py +0 -0
  166. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/HttpTextEdit.py +0 -0
  167. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/LinksBar.py +0 -0
  168. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/ProjectCard.py +0 -0
  169. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/UpdateCard.py +0 -0
  170. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/VersionCard.py +0 -0
  171. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/about/__init__.py +0 -0
  172. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/OKIcon.py +0 -0
  173. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/__init__.py +0 -0
  174. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/accent_color.py +0 -0
  175. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/config.py +0 -0
  176. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/design_system.py +0 -0
  177. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/icons.py +0 -0
  178. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/common/style_sheet.py +0 -0
  179. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/DebugTab.py +0 -0
  180. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/JobControls.py +0 -0
  181. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/OverlayWidget.py +0 -0
  182. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/RunCodeTab.py +0 -0
  183. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/Screenshot.py +0 -0
  184. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/debug/__init__.py +0 -0
  185. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/events.py +0 -0
  186. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/GettextTranslator.py +0 -0
  187. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/__init__.py +0 -0
  188. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/en_US.qm +0 -0
  189. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/en_US.ts +0 -0
  190. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/es_ES.qm +0 -0
  191. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/es_ES.ts +0 -0
  192. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/ja_JP.qm +0 -0
  193. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/ja_JP.ts +0 -0
  194. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/ko_KR.qm +0 -0
  195. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/ko_KR.ts +0 -0
  196. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/path.py +0 -0
  197. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/update.py +0 -0
  198. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/zh_CN.qm +0 -0
  199. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/zh_CN.ts +0 -0
  200. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/zh_TW.qm +0 -0
  201. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/i18n/zh_TW.ts +0 -0
  202. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/overlay/OverlayWindow.py +0 -0
  203. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/overlay/__init__.py +0 -0
  204. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/plugins/PluginTab.py +0 -0
  205. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/plugins/__init__.py +0 -0
  206. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/plugins/imported_tabs.py +0 -0
  207. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/__init__.py +0 -0
  208. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/card.qss +0 -0
  209. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/discord.svg +0 -0
  210. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/heart.svg +0 -0
  211. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/message_window.qss +0 -0
  212. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/setting_interface.qss +0 -0
  213. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/status_bar.qss +0 -0
  214. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/stop.svg +0 -0
  215. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/dark/tab.qss +0 -0
  216. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/card.qss +0 -0
  217. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/discord.svg +0 -0
  218. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/heart.svg +0 -0
  219. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/message_window.qss +0 -0
  220. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/setting_interface.qss +0 -0
  221. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/status_bar.qss +0 -0
  222. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/stop.svg +0 -0
  223. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qss/light/tab.qss +0 -0
  224. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/qt.qrc +0 -0
  225. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/resources.py +0 -0
  226. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/settings/GlobalConfigCard.py +0 -0
  227. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/settings/GlobalConfigTab.py +0 -0
  228. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/settings/SettingTab.py +0 -0
  229. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/settings/__init__.py +0 -0
  230. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/LogWindow.py +0 -0
  231. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/SelectCaptureListView.py +0 -0
  232. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/SelectInteractionListView.py +0 -0
  233. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/StartCard.py +0 -0
  234. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/StartTab.py +0 -0
  235. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/start/__init__.py +0 -0
  236. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ConfigCard.py +0 -0
  237. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ConfigItemFactory.py +0 -0
  238. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ConfigLabelAndWidget.py +0 -0
  239. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/EditTaskTab.py +0 -0
  240. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndButtons.py +0 -0
  241. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndDoubleSpinBox.py +0 -0
  242. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndDropDown.py +0 -0
  243. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndFileSelector.py +0 -0
  244. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndGlobal.py +0 -0
  245. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndLineEdit.py +0 -0
  246. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndList.py +0 -0
  247. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndMcpServer.py +0 -0
  248. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndMultiSelection.py +0 -0
  249. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndSpinBox.py +0 -0
  250. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndSwitchButton.py +0 -0
  251. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndTextEdit.py +0 -0
  252. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/LabelAndWidget.py +0 -0
  253. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/MarkUpWindow.py +0 -0
  254. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ModifyListDialog.py +0 -0
  255. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ModifyListItem.py +0 -0
  256. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/OneTimeTaskTab.py +0 -0
  257. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/PythonHighlighter.py +0 -0
  258. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/RecordScript.py +0 -0
  259. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ScheduleTaskTab.py +0 -0
  260. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/ScriptPackager.py +0 -0
  261. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/StartButton.py +0 -0
  262. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TaskCard.py +0 -0
  263. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TaskManger.py +0 -0
  264. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TaskOpButton.py +0 -0
  265. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TaskTab.py +0 -0
  266. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TemplateFactory.py +0 -0
  267. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TemplateTab.py +0 -0
  268. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TooltipTableWidget.py +0 -0
  269. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/TriggerTaskTab.py +0 -0
  270. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/__init__.py +0 -0
  271. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/tasks/schedule_index_sync.py +0 -0
  272. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/Alert.py +0 -0
  273. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/InitWorker.py +0 -0
  274. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/__init__.py +0 -0
  275. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/app.py +0 -0
  276. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/download.py +0 -0
  277. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/pip_util.py +0 -0
  278. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/pyappify_startup.py +0 -0
  279. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/touch_scroll.py +0 -0
  280. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/util/windows_thumbnail.py +0 -0
  281. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/BaseLoading.py +0 -0
  282. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/BaseWindow.py +0 -0
  283. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/Card.py +0 -0
  284. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/CustomTab.py +0 -0
  285. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/EmptyCard.py +0 -0
  286. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/ExpandCardLayout.py +0 -0
  287. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/FlowLayout.py +0 -0
  288. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/FramelessDialog.py +0 -0
  289. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/ImageWidget.py +0 -0
  290. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/ImportWarningDialog.py +0 -0
  291. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/ListTableWidgetItem.py +0 -0
  292. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/NumericTableWidgetItem.py +0 -0
  293. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/OkCompactSpinBox.py +0 -0
  294. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/SortingTableWidgetItem.py +0 -0
  295. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/StartLoadingDialog.py +0 -0
  296. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/StatusBar.py +0 -0
  297. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/Tab.py +0 -0
  298. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/TabWidget.py +0 -0
  299. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/UpdateConfigWidgetItem.py +0 -0
  300. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/WidgetWithVLabel.py +0 -0
  301. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/YesNonWidgetItem.py +0 -0
  302. {ok_script-2.0.18 → ok_script-2.0.19}/ok/ui/qt/widget/__init__.py +0 -0
  303. {ok_script-2.0.18 → ok_script-2.0.19}/ok/update/__init__.py +0 -0
  304. {ok_script-2.0.18 → ok_script-2.0.19}/ok/update/copy_ok_folder.py +0 -0
  305. {ok_script-2.0.18 → ok_script-2.0.19}/ok/update/inline_ok_requirements.py +0 -0
  306. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/Analytics.py +0 -0
  307. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/GlobalConfig.py +0 -0
  308. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/__init__.py +0 -0
  309. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/blur.py +0 -0
  310. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/clazz.py +0 -0
  311. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/collection.py +0 -0
  312. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/color.py +0 -0
  313. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/config.py +0 -0
  314. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/explorer.py +0 -0
  315. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/file.py +0 -0
  316. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/gpu_driver_settings.py +0 -0
  317. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/handler.py +0 -0
  318. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/i18n.py +0 -0
  319. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/logger.py +0 -0
  320. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/partial_sync_repo.py +0 -0
  321. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/print_hwnd.py +0 -0
  322. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/process.py +0 -0
  323. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/version.py +0 -0
  324. {ok_script-2.0.18 → ok_script-2.0.19}/ok/util/windows_schedule.py +0 -0
  325. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/dependency_links.txt +0 -0
  326. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/entry_points.txt +0 -0
  327. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/not-zip-safe +0 -0
  328. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/requires.txt +0 -0
  329. {ok_script-2.0.18 → ok_script-2.0.19}/ok_script.egg-info/top_level.txt +0 -0
  330. {ok_script-2.0.18 → ok_script-2.0.19}/pyproject.toml +0 -0
  331. {ok_script-2.0.18 → ok_script-2.0.19}/setup.cfg +0 -0
  332. {ok_script-2.0.18 → ok_script-2.0.19}/setup.py +0 -0
  333. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_accent_color.py +0 -0
  334. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_app.py +0 -0
  335. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_base_interaction.py +0 -0
  336. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_blur.py +0 -0
  337. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_box.py +0 -0
  338. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_capture_update.py +0 -0
  339. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_cli.py +0 -0
  340. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_config_card.py +0 -0
  341. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_core_events.py +0 -0
  342. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_core_ui_services.py +0 -0
  343. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_debug_job_controls.py +0 -0
  344. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_device_manager.py +0 -0
  345. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_executor_jobs.py +0 -0
  346. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_expand_card_layout.py +0 -0
  347. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_explorer.py +0 -0
  348. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_global_config.py +0 -0
  349. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_gpu_driver_settings.py +0 -0
  350. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_handler.py +0 -0
  351. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_headless_imports.py +0 -0
  352. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_inline_ok_requirements.py +0 -0
  353. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_logger.py +0 -0
  354. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_main_window_notifications.py +0 -0
  355. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_main_window_startup_tab.py +0 -0
  356. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_main_window_system_theme.py +0 -0
  357. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_mcp_runner.py +0 -0
  358. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_mcp_server.py +0 -0
  359. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_mcp_setting.py +0 -0
  360. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_missing_frame.py +0 -0
  361. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_navigation_state.py +0 -0
  362. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_notifications.py +0 -0
  363. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_ok_mutex.py +0 -0
  364. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_overlay_custom_draw.py +0 -0
  365. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_overlay_lifecycle.py +0 -0
  366. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_package_metadata.py +0 -0
  367. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_plugin_staging.py +0 -0
  368. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_plugin_tabs.py +0 -0
  369. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_plugins.py +0 -0
  370. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_process.py +0 -0
  371. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_process_mutex.py +0 -0
  372. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_pyappify_startup_update.py +0 -0
  373. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_qt_events.py +0 -0
  374. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_qt_legacy_imports.py +0 -0
  375. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_qt_page_layout.py +0 -0
  376. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_runtime_startup.py +0 -0
  377. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_schedule_startup.py +0 -0
  378. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_schedule_task_index_sync.py +0 -0
  379. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_screenshot_naming.py +0 -0
  380. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_screenshot_rendering.py +0 -0
  381. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_start_controller.py +0 -0
  382. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_start_tab_overlay.py +0 -0
  383. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_task_executor_queue.py +0 -0
  384. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_task_reloading.py +0 -0
  385. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_task_ui.py +0 -0
  386. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_template_compression.py +0 -0
  387. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_template_generation.py +0 -0
  388. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_template_tab.py +0 -0
  389. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_touch_scroll.py +0 -0
  390. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_translation_fallback.py +0 -0
  391. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_ui_config.py +0 -0
  392. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_version.py +0 -0
  393. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_windows_graphics_capture.py +0 -0
  394. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_windows_graphics_hdr.py +0 -0
  395. {ok_script-2.0.18 → ok_script-2.0.19}/tests/test_windows_schedule_target_parse.py +0 -0
  396. {ok_script-2.0.18 → ok_script-2.0.19}/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
- For screenshot annotations and named template features, use [generate-templates](../generate-templates/SKILL.md): retain originals and COCO annotations in `ok_templates`, export individual PNGs with `generate_templates` into `assets/templates`, and verify `find_feature`/`find_one` using the original feature names. Existing packed COCO assets and `coco_feature_json` remain supported. The split loader reports malformed filenames; fix the indicated asset instead of lowering matching thresholds or ignoring the error.
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 template matching assets for a third-party ok-script application from its screenshots and COCO annotations, then verify them with find_feature or find_one.
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, follow the project-creation handoff below.
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
- - Store reproducible screenshots under the target project's `tests/images/`, or reuse an existing tracked `ok_templates` source when appropriate. Confirm each fixture exists and loads.
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.18
3
+ Version: 2.0.19
4
4
  Summary: Automation with Computer Vision for Python
5
5
  Author-email: ok-oldking <firedcto@gmail.com>
6
6
  License: ok-script License
@@ -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. No MCP
31
- server is needed to read the setup instructions.
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 a successful initial installation, ask: "Would you like to create an
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
- 5. When project creation is requested, read the
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. Omit `gui_icon` to use the default `OK` PNG bundled with
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
- 6. Run the checks in the relevant skills. Report the environment path, installed
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. For application setup, also report the project folder, config,
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
- # MuMuPlayer12 5.0
222
- os.path.abspath(os.path.join(nemu_folder, './nx_device/12.0/shell/sdk/external_renderer_ipc.dll')),
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=0
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. '
@@ -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 = "mumu player 12 only"
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
- f'vms/MuMuPlayer-12.0-{self.emulator.player_id}/configs/customer_config.json'))
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:
@@ -271,6 +271,10 @@ def compare_path_safe(str1, str2):
271
271
 
272
272
 
273
273
  def get_player_id_from_cmdline(cmdline):
274
+ # MuMu can put --restart-last-pid before its instance index.
275
+ for i, arg in enumerate(cmdline[:-1]):
276
+ if arg == '-v' and cmdline[i + 1].isdigit():
277
+ return int(cmdline[i + 1])
274
278
  for i in range(len(cmdline)):
275
279
  if i != 0:
276
280
  if cmdline[i].isdigit():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ok-script
3
- Version: 2.0.18
3
+ Version: 2.0.19
4
4
  Summary: Automation with Computer Vision for Python
5
5
  Author-email: ok-oldking <firedcto@gmail.com>
6
6
  License: ok-script License
@@ -11,6 +11,7 @@ setup.py
11
11
  .agents/skills/reload-tasks/agents/openai.yaml
12
12
  .agents/skills/setup-env/SKILL.md
13
13
  .agents/skills/setup-env/agents/openai.yaml
14
+ .agents/skills/setup-env/assets/ok-script-develop/SKILL.md
14
15
  .agents/skills/setup-project/SKILL.md
15
16
  .agents/skills/setup-project/agents/openai.yaml
16
17
  .agents/skills/use_venv/SKILL.md
@@ -0,0 +1,84 @@
1
+ import threading
2
+ import os
3
+ import unittest
4
+ from types import SimpleNamespace
5
+ from unittest.mock import Mock, mock_open, patch
6
+
7
+ from ok.device.capture_methods.nemu_ipc import NemuIpcCaptureMethod
8
+ from ok.capture.adb.nemu_ipc import NemuIpcImpl
9
+ from ok.util.window import get_player_id_from_cmdline
10
+
11
+
12
+ class TestNemuIpcCaptureMethod(unittest.TestCase):
13
+ def make_capture(self):
14
+ device_manager = SimpleNamespace()
15
+ capture = NemuIpcCaptureMethod(device_manager, threading.Event())
16
+ capture.emulator = SimpleNamespace(path=r'C:\MuMu\shell\MuMuPlayer.exe', player_id=0)
17
+ return capture
18
+
19
+ def test_initialized_capture_reuses_connection_without_rechecking_config(self):
20
+ capture = self.make_capture()
21
+ capture.nemu_impl = SimpleNamespace(screenshot=Mock(return_value='frame'))
22
+ capture.check_mumu_app_keep_alive_400 = Mock()
23
+
24
+ self.assertEqual('frame', capture.do_get_frame())
25
+ self.assertEqual('frame', capture.do_get_frame())
26
+
27
+ capture.check_mumu_app_keep_alive_400.assert_not_called()
28
+ self.assertEqual(2, capture.nemu_impl.screenshot.call_count)
29
+
30
+ def test_first_capture_initializes_then_uses_screenshot(self):
31
+ capture = self.make_capture()
32
+ implementation = SimpleNamespace(screenshot=Mock(return_value='frame'))
33
+ capture.check_mumu_app_keep_alive_400 = Mock()
34
+
35
+ with patch('ok.capture.adb.nemu_ipc.NemuIpc', return_value=implementation):
36
+ self.assertEqual('frame', capture.do_get_frame())
37
+
38
+ capture.check_mumu_app_keep_alive_400.assert_called_once_with()
39
+ implementation.screenshot.assert_called_once_with(timeout=0.5)
40
+
41
+ def test_legacy_mumu_loads_sdk_from_shell(self):
42
+ root = os.path.abspath('MuMu')
43
+ expected = os.path.join(root, 'shell', 'sdk', 'external_renderer_ipc.dll')
44
+ with patch('ok.capture.adb.nemu_ipc.os.path.exists', side_effect=lambda path: path == expected), \
45
+ patch('ok.capture.adb.nemu_ipc.ctypes.CDLL') as load:
46
+ NemuIpcImpl(root, 0)
47
+ load.assert_called_once_with(expected)
48
+
49
+ def test_mumu_15_capture_passes_selected_runtime_version(self):
50
+ capture = self.make_capture()
51
+ capture.emulator.name = 'MuMuPlayer-15.0-0'
52
+ capture.check_mumu_app_keep_alive_400 = Mock()
53
+ with patch('ok.capture.adb.nemu_ipc.NemuIpc') as implementation:
54
+ capture.init_nemu()
55
+ implementation.assert_called_once_with(
56
+ nemu_folder=capture.base_folder(), instance_id=0,
57
+ display_id=0, runtime_version='15.0')
58
+
59
+ def test_mumu_15_loads_sdk_from_selected_runtime(self):
60
+ root = os.path.abspath('MuMu')
61
+ expected = os.path.join(root, 'nx_device', '15.0', 'shell', 'sdk', 'external_renderer_ipc.dll')
62
+ with patch('ok.capture.adb.nemu_ipc.os.path.exists', side_effect=lambda path: path == expected), \
63
+ patch('ok.capture.adb.nemu_ipc.ctypes.CDLL') as load:
64
+ NemuIpcImpl(root, 0, runtime_version='15.0')
65
+ load.assert_called_once_with(expected)
66
+
67
+ def test_keep_alive_check_uses_actual_instance_name(self):
68
+ capture = self.make_capture()
69
+ capture.emulator.name = 'MuMuPlayer-15.0-0'
70
+ file = mock_open(read_data='{"customer": {"app_keptlive": "true"}}')
71
+ with patch('builtins.open', file), self.assertRaisesRegex(Exception, 'background keep alive'):
72
+ capture.check_mumu_app_keep_alive_400()
73
+ file.assert_called_once_with(os.path.join(
74
+ capture.base_folder(), 'vms', 'MuMuPlayer-15.0-0', 'configs', 'customer_config.json'),
75
+ mode='r', encoding='utf-8')
76
+
77
+ def test_mumu_restart_pid_does_not_override_instance_index(self):
78
+ self.assertEqual(0, get_player_id_from_cmdline([
79
+ 'MuMuNxDevice.exe', '-r', 'true', '--restart-last-pid', '55708',
80
+ '-v', '0', '--vm', 'MuMuPlayer-15.0-0']))
81
+
82
+
83
+ if __name__ == '__main__':
84
+ unittest.main()
@@ -66,6 +66,8 @@ def test_incremental_build_bundles_only_current_consumer_skills(tmp_path, monkey
66
66
  assert not stale.exists()
67
67
  assert not (destination / 'pyproject.toml').exists()
68
68
  assert (destination / 'docs/agent-setup.md').read_bytes() == (root / 'docs/agent-setup.md').read_bytes()
69
+ template = Path('.agents/skills/setup-env/assets/ok-script-develop/SKILL.md')
70
+ assert (destination / template).read_bytes() == (root / template).read_bytes()
69
71
  monkeypatch.setattr(skills, '__file__', str(Path(command.build_lib) / 'ok/core/skills.py'))
70
72
  catalog = skills.list_skills()
71
73
  assert {skill['id'] for skill in catalog} == CONSUMER_SKILLS
@@ -1,40 +0,0 @@
1
- import threading
2
- import unittest
3
- from types import SimpleNamespace
4
- from unittest.mock import Mock, patch
5
-
6
- from ok.device.capture_methods.nemu_ipc import NemuIpcCaptureMethod
7
-
8
-
9
- class TestNemuIpcCaptureMethod(unittest.TestCase):
10
- def make_capture(self):
11
- device_manager = SimpleNamespace()
12
- capture = NemuIpcCaptureMethod(device_manager, threading.Event())
13
- capture.emulator = SimpleNamespace(path=r'C:\MuMu\shell\MuMuPlayer.exe', player_id=0)
14
- return capture
15
-
16
- def test_initialized_capture_reuses_connection_without_rechecking_config(self):
17
- capture = self.make_capture()
18
- capture.nemu_impl = SimpleNamespace(screenshot=Mock(return_value='frame'))
19
- capture.check_mumu_app_keep_alive_400 = Mock()
20
-
21
- self.assertEqual('frame', capture.do_get_frame())
22
- self.assertEqual('frame', capture.do_get_frame())
23
-
24
- capture.check_mumu_app_keep_alive_400.assert_not_called()
25
- self.assertEqual(2, capture.nemu_impl.screenshot.call_count)
26
-
27
- def test_first_capture_initializes_then_uses_screenshot(self):
28
- capture = self.make_capture()
29
- implementation = SimpleNamespace(screenshot=Mock(return_value='frame'))
30
- capture.check_mumu_app_keep_alive_400 = Mock()
31
-
32
- with patch('ok.capture.adb.nemu_ipc.NemuIpc', return_value=implementation):
33
- self.assertEqual('frame', capture.do_get_frame())
34
-
35
- capture.check_mumu_app_keep_alive_400.assert_called_once_with()
36
- implementation.screenshot.assert_called_once_with(timeout=0.5)
37
-
38
-
39
- if __name__ == '__main__':
40
- unittest.main()