rf-mcp 0.34.0.dev0__tar.gz → 0.34.0.dev2__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 (263) hide show
  1. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/PKG-INFO +6 -2
  2. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/README.md +2 -1
  3. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/pyproject.toml +16 -1
  4. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/platynui_focus.py +2 -2
  5. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/suite_execution_service.py +69 -9
  6. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/library_checker.py +4 -1
  7. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.gitignore +0 -0
  8. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/@msgpackr-extract/msgpackr-extract-linux-x64/README.md +0 -0
  9. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/@standard-schema/spec/LICENSE +0 -0
  10. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/@standard-schema/spec/README.md +0 -0
  11. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/cross-spawn/LICENSE +0 -0
  12. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/cross-spawn/README.md +0 -0
  13. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/detect-libc/LICENSE +0 -0
  14. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/detect-libc/README.md +0 -0
  15. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/effect/LICENSE +0 -0
  16. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/effect/README.md +0 -0
  17. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/fast-check/LICENSE +0 -0
  18. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/fast-check/README.md +0 -0
  19. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/find-my-way-ts/LICENSE +0 -0
  20. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/find-my-way-ts/README.md +0 -0
  21. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/ini/LICENSE +0 -0
  22. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/ini/README.md +0 -0
  23. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/isexe/LICENSE +0 -0
  24. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/isexe/README.md +0 -0
  25. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/kubernetes-types/README.md +0 -0
  26. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/msgpackr/LICENSE +0 -0
  27. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/msgpackr/README.md +0 -0
  28. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/msgpackr-extract/LICENSE +0 -0
  29. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/msgpackr-extract/README.md +0 -0
  30. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/multipasta/LICENSE +0 -0
  31. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/multipasta/README.md +0 -0
  32. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/node-gyp-build-optional-packages/LICENSE +0 -0
  33. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/node-gyp-build-optional-packages/README.md +0 -0
  34. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/pure-rand/LICENSE +0 -0
  35. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/pure-rand/README.md +0 -0
  36. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/toml/LICENSE +0 -0
  37. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/toml/README.md +0 -0
  38. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/uuid/README.md +0 -0
  39. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/which/LICENSE +0 -0
  40. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/which/README.md +0 -0
  41. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/yaml/LICENSE +0 -0
  42. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/yaml/README.md +0 -0
  43. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/zod/LICENSE +0 -0
  44. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/.kilo/node_modules/zod/README.md +0 -0
  45. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/LICENSE +0 -0
  46. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/__init__.py +0 -0
  47. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/__init__.py +0 -0
  48. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/adapter_factory.py +0 -0
  49. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/browser_adapter.py +0 -0
  50. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/page_state_adapter.py +0 -0
  51. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/playwright_adapter.py +0 -0
  52. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/recovery_adapter.py +0 -0
  53. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/adapters/selenium_adapter.py +0 -0
  54. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/attach/__init__.py +0 -0
  55. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/attach/mcp_attach.py +0 -0
  56. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/compat/__init__.py +0 -0
  57. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/compat/fastmcp_compat.py +0 -0
  58. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/__init__.py +0 -0
  59. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/browser/__init__.py +0 -0
  60. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/browser/browser_library_manager.py +0 -0
  61. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/__init__.py +0 -0
  62. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/desktop_display_safety.py +0 -0
  63. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/desktop_execution_signals.py +0 -0
  64. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/desktop_guidance.py +0 -0
  65. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/desktop_launch_env.py +0 -0
  66. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/execution_coordinator.py +0 -0
  67. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/external_rf_client.py +0 -0
  68. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/keyword_executor.py +0 -0
  69. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/locator_arg_introspection.py +0 -0
  70. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/locator_converter.py +0 -0
  71. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/mobile_capability_service.py +0 -0
  72. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/page_source_service.py +0 -0
  73. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/rf_native_context_manager.py +0 -0
  74. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/session_manager.py +0 -0
  75. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/execution/ui_tree_service.py +0 -0
  76. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/keyword_matcher.py +0 -0
  77. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/library_recommender.py +0 -0
  78. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/nlp_processor.py +0 -0
  79. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/state_manager.py +0 -0
  80. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/test_builder.py +0 -0
  81. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/variables/__init__.py +0 -0
  82. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/components/variables/variable_resolver.py +0 -0
  83. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/config/__init__.py +0 -0
  84. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/config/library_registry.py +0 -0
  85. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/container.py +0 -0
  86. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/__init__.py +0 -0
  87. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/dynamic_keyword_orchestrator.py +0 -0
  88. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/event_bus.py +0 -0
  89. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/keyword_discovery.py +0 -0
  90. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/library_manager.py +0 -0
  91. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/core/session_manager.py +0 -0
  92. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/__init__.py +0 -0
  93. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/__init__.py +0 -0
  94. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/aggregates.py +0 -0
  95. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/entities.py +0 -0
  96. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/events.py +0 -0
  97. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/services.py +0 -0
  98. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/artifact_output/value_objects.py +0 -0
  99. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/__init__.py +0 -0
  100. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/aggregates.py +0 -0
  101. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/entities.py +0 -0
  102. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/events.py +0 -0
  103. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/services.py +0 -0
  104. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/batch_execution/value_objects.py +0 -0
  105. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/__init__.py +0 -0
  106. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/adapters/__init__.py +0 -0
  107. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/adapters/fastmcp_adapter.py +0 -0
  108. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/aggregates.py +0 -0
  109. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/entities.py +0 -0
  110. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/events.py +0 -0
  111. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/repository.py +0 -0
  112. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/security.py +0 -0
  113. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/services.py +0 -0
  114. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/instruction/value_objects.py +0 -0
  115. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/__init__.py +0 -0
  116. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/adapters/__init__.py +0 -0
  117. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/adapters/locator_normalizer_adapter.py +0 -0
  118. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/adapters/mcp_tool.py +0 -0
  119. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/adapters/session_lookup_adapter.py +0 -0
  120. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/aggregates.py +0 -0
  121. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/entities.py +0 -0
  122. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/events.py +0 -0
  123. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/services.py +0 -0
  124. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/intent/value_objects.py +0 -0
  125. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/keyword_resolution/__init__.py +0 -0
  126. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/keyword_resolution/aggregates.py +0 -0
  127. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/keyword_resolution/events.py +0 -0
  128. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/keyword_resolution/services.py +0 -0
  129. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/keyword_resolution/value_objects.py +0 -0
  130. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/__init__.py +0 -0
  131. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/adapters/__init__.py +0 -0
  132. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/adapters/fastmcp_adapter.py +0 -0
  133. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/adapters/sqlite_vec_adapter.py +0 -0
  134. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/aggregates.py +0 -0
  135. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/entities.py +0 -0
  136. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/events.py +0 -0
  137. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/repository.py +0 -0
  138. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/services.py +0 -0
  139. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/memory/value_objects.py +0 -0
  140. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/__init__.py +0 -0
  141. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/aggregates.py +0 -0
  142. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/entities.py +0 -0
  143. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/events.py +0 -0
  144. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/services.py +0 -0
  145. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/recovery/value_objects.py +0 -0
  146. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/__init__.py +0 -0
  147. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/aggregates.py +0 -0
  148. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/events.py +0 -0
  149. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/repository.py +0 -0
  150. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/services.py +0 -0
  151. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/response_optimization/value_objects.py +0 -0
  152. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/shared/__init__.py +0 -0
  153. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/shared/kernel.py +0 -0
  154. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/__init__.py +0 -0
  155. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/aggregates.py +0 -0
  156. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/delta_aggregates.py +0 -0
  157. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/delta_entities.py +0 -0
  158. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/delta_events.py +0 -0
  159. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/delta_service.py +0 -0
  160. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/delta_value_objects.py +0 -0
  161. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/diff_service.py +0 -0
  162. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/entities.py +0 -0
  163. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/events.py +0 -0
  164. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/list_folding.py +0 -0
  165. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/models.py +0 -0
  166. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/repository.py +0 -0
  167. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/services.py +0 -0
  168. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/snapshot/value_objects.py +0 -0
  169. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/__init__.py +0 -0
  170. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/aggregates.py +0 -0
  171. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/entities.py +0 -0
  172. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/events.py +0 -0
  173. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/keyword_classifier.py +0 -0
  174. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/services.py +0 -0
  175. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/timeout/value_objects.py +0 -0
  176. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/__init__.py +0 -0
  177. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/aggregates.py +0 -0
  178. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/entities.py +0 -0
  179. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/events.py +0 -0
  180. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/repository.py +0 -0
  181. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/services.py +0 -0
  182. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/token_accounting/value_objects.py +0 -0
  183. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/__init__.py +0 -0
  184. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/adapters/__init__.py +0 -0
  185. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/adapters/fastmcp_adapter.py +0 -0
  186. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/aggregates.py +0 -0
  187. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/entities.py +0 -0
  188. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/events.py +0 -0
  189. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/repository.py +0 -0
  190. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/services.py +0 -0
  191. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/domains/tool_profile/value_objects.py +0 -0
  192. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/entry.py +0 -0
  193. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/__init__.py +0 -0
  194. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/api.py +0 -0
  195. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/apps.py +0 -0
  196. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/asgi.py +0 -0
  197. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/bridge.py +0 -0
  198. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/config.py +0 -0
  199. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/controller.py +0 -0
  200. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/devserver.py +0 -0
  201. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/django_app.py +0 -0
  202. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/static/frontend/app.js +0 -0
  203. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/static/frontend/base.css +0 -0
  204. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/templates/frontend/index.html +0 -0
  205. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/templates/frontend/layout.html +0 -0
  206. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/urls.py +0 -0
  207. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/frontend/views.py +0 -0
  208. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/__init__.py +0 -0
  209. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/browser_models.py +0 -0
  210. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/config_models.py +0 -0
  211. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/execution_models.py +0 -0
  212. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/library_models.py +0 -0
  213. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/models/session_models.py +0 -0
  214. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/__init__.py +0 -0
  215. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/adapters.py +0 -0
  216. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/cli.py +0 -0
  217. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/codecs.py +0 -0
  218. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/diagnostics.py +0 -0
  219. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/installer.py +0 -0
  220. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/onboarding/manifest.py +0 -0
  221. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/__init__.py +0 -0
  222. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/collector.py +0 -0
  223. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/compression_learner.py +0 -0
  224. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/folding_learner.py +0 -0
  225. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/instruction_hooks.py +0 -0
  226. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/instruction_learner.py +0 -0
  227. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/page_analyzer.py +0 -0
  228. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/pattern_store.py +0 -0
  229. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/ref_learner.py +0 -0
  230. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/optimization/timeout_learner.py +0 -0
  231. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/__init__.py +0 -0
  232. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/base.py +0 -0
  233. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/__init__.py +0 -0
  234. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/browser_plugin.py +0 -0
  235. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/definitions.py +0 -0
  236. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/platynui_plugin.py +0 -0
  237. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/requests_plugin.py +0 -0
  238. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/builtin/selenium_plugin.py +0 -0
  239. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/contracts.py +0 -0
  240. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/discovery.py +0 -0
  241. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/plugins/manager.py +0 -0
  242. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/server.py +0 -0
  243. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/__init__.py +0 -0
  244. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/argument_processor.py +0 -0
  245. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/enhanced_response_serializer.py +0 -0
  246. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/enhanced_serialization_integration.py +0 -0
  247. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/hints.py +0 -0
  248. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/libdoc_argument_parser.py +0 -0
  249. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/library_detection.py +0 -0
  250. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/library_detector.py +0 -0
  251. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/library_loading_validator.py +0 -0
  252. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/logging_setup.py +0 -0
  253. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/requests_guidance.py +0 -0
  254. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/response_serializer.py +0 -0
  255. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/rf_libdoc_integration.py +0 -0
  256. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/rf_native_type_converter.py +0 -0
  257. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/rf_variables_compatibility.py +0 -0
  258. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/sampling.py +0 -0
  259. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/server_integration.py +0 -0
  260. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/session_resolution.py +0 -0
  261. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/token_efficient_output.py +0 -0
  262. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/validation.py +0 -0
  263. {rf_mcp-0.34.0.dev0 → rf_mcp-0.34.0.dev2}/src/robotmcp/utils/visual_guidance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rf-mcp
3
- Version: 0.34.0.dev0
3
+ Version: 0.34.0.dev2
4
4
  Summary: Robot Framework MCP Server - Natural Language Test Automation Bridge
5
5
  Project-URL: Homepage, https://github.com/manykarim/rf-mcp
6
6
  Project-URL: Repository, https://github.com/manykarim/rf-mcp
@@ -33,6 +33,9 @@ Provides-Extra: api
33
33
  Requires-Dist: robotframework-requests; extra == 'api'
34
34
  Provides-Extra: database
35
35
  Requires-Dist: robotframework-databaselibrary; extra == 'database'
36
+ Provides-Extra: desktop
37
+ Requires-Dist: platynui-cli==0.13.0.dev2; (python_version >= '3.12') and extra == 'desktop'
38
+ Requires-Dist: robotframework-platynui==0.13.0.dev2; (python_version >= '3.12') and extra == 'desktop'
36
39
  Provides-Extra: frontend
37
40
  Requires-Dist: django<5.0,>=4.2; extra == 'frontend'
38
41
  Requires-Dist: uvicorn[standard]>=0.24; extra == 'frontend'
@@ -221,10 +224,11 @@ uv pip install rf-mcp[web] # Browser Library + SeleniumLibrary
221
224
  uv pip install rf-mcp[mobile] # AppiumLibrary
222
225
  uv pip install rf-mcp[api] # RequestsLibrary
223
226
  uv pip install rf-mcp[database] # DatabaseLibrary
227
+ uv pip install --pre rf-mcp[desktop] # PlatynUI new-core (Rust) native desktop — Python 3.12+, prerelease
224
228
  uv pip install rf-mcp[frontend] # Django-based web frontend dashboard
225
229
  uv pip install rf-mcp[memory] # Persistent semantic memory (sqlite-vec + model2vec)
226
230
  uv pip install rf-mcp[semantic] # Sentence-transformers for find_keywords embedding ranking
227
- uv pip install rf-mcp[all] # All optional Robot Framework libraries
231
+ uv pip install rf-mcp[all] # All optional Robot Framework libraries (desktop is separate — prerelease/3.12+)
228
232
 
229
233
  # Alternatively, add to an existing uv project
230
234
  uv init
@@ -167,10 +167,11 @@ uv pip install rf-mcp[web] # Browser Library + SeleniumLibrary
167
167
  uv pip install rf-mcp[mobile] # AppiumLibrary
168
168
  uv pip install rf-mcp[api] # RequestsLibrary
169
169
  uv pip install rf-mcp[database] # DatabaseLibrary
170
+ uv pip install --pre rf-mcp[desktop] # PlatynUI new-core (Rust) native desktop — Python 3.12+, prerelease
170
171
  uv pip install rf-mcp[frontend] # Django-based web frontend dashboard
171
172
  uv pip install rf-mcp[memory] # Persistent semantic memory (sqlite-vec + model2vec)
172
173
  uv pip install rf-mcp[semantic] # Sentence-transformers for find_keywords embedding ranking
173
- uv pip install rf-mcp[all] # All optional Robot Framework libraries
174
+ uv pip install rf-mcp[all] # All optional Robot Framework libraries (desktop is separate — prerelease/3.12+)
174
175
 
175
176
  # Alternatively, add to an existing uv project
176
177
  uv init
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "rf-mcp"
7
- version = "0.34.0.dev0"
7
+ version = "0.34.0.dev2"
8
8
  description = "Robot Framework MCP Server - Natural Language Test Automation Bridge"
9
9
  authors = [{ name = "Many Kasiriha" }]
10
10
  license = { text = "Apache-2.0" }
@@ -28,6 +28,21 @@ frontend = ["django>=4.2,<5.0", "uvicorn[standard]>=0.24"]
28
28
  mobile = ["robotframework-appiumlibrary"]
29
29
  api = ["robotframework-requests"]
30
30
  database = ["robotframework-databaselibrary"]
31
+ # PlatynUI new-core (Rust) native desktop automation (ADR-025). These are DEV
32
+ # PRERELEASES tracking the latest Rust core and REQUIRE Python 3.12+ (the native
33
+ # core ships cp312-abi3 wheels; robotframework-PlatynUI declares requires-python
34
+ # >=3.12). The `python_version >= "3.12"` markers keep `pip install rf-mcp[desktop]`
35
+ # resolvable on rf-mcp's 3.10/3.11 baseline (it just installs nothing there).
36
+ # robotframework-PlatynUI pins `platynui-native==<same version>`, so the native
37
+ # Rust core is pulled automatically at the matching version — do NOT pin it
38
+ # separately (that risks a lockstep conflict on the next bump). platynui-cli is the
39
+ # optional diagnostic CLI (window/snapshot/highlight, used by the display-safety
40
+ # probes). Exact-pinned for reproducibility; bump both together to a newer dev.
41
+ # The version references a prerelease, so resolvers accept it WITHOUT a global --pre.
42
+ desktop = [
43
+ "robotframework-PlatynUI==0.13.0.dev2; python_version >= '3.12'",
44
+ "platynui-cli==0.13.0.dev2; python_version >= '3.12'",
45
+ ]
31
46
  memory = ["sqlite-vec>=0.1.6", "model2vec>=0.4.0"]
32
47
  tokens = ["tiktoken>=0.7.0"]
33
48
  # OBS-30 / lazy-offline-embeddings — semantic find_keywords ranking runs on a
@@ -1052,7 +1052,7 @@ def x11_window_present(
1052
1052
  try:
1053
1053
  proc = subprocess.run(
1054
1054
  [sys.executable, "-c", _X11_WINDOW_PROBE_SRC, *names],
1055
- capture_output=True, text=True, timeout=5, env=env,
1055
+ capture_output=True, text=True, timeout=5, env=env, stdin=subprocess.DEVNULL,
1056
1056
  )
1057
1057
  out = (proc.stdout or "").strip()
1058
1058
  return out if out in ("present", "absent", "unknown") else "unknown"
@@ -1143,7 +1143,7 @@ def x11_display_pids() -> Optional[frozenset]:
1143
1143
  try:
1144
1144
  proc = subprocess.run(
1145
1145
  [sys.executable, "-c", _X11_PID_LIST_PROBE_SRC],
1146
- capture_output=True, text=True, timeout=5, env=dict(os.environ),
1146
+ capture_output=True, text=True, timeout=5, env=dict(os.environ), stdin=subprocess.DEVNULL,
1147
1147
  )
1148
1148
  out = (proc.stdout or "").strip()
1149
1149
  if not out or out == "unknown":
@@ -13,6 +13,7 @@ import json
13
13
  import io
14
14
  import subprocess
15
15
  import sys
16
+ import signal
16
17
  from contextlib import redirect_stdout, redirect_stderr
17
18
 
18
19
  try:
@@ -31,6 +32,37 @@ from robotmcp.models.config_models import ExecutionConfig
31
32
  logger = logging.getLogger(__name__)
32
33
 
33
34
 
35
+ def _kill_process_tree(proc: "subprocess.Popen") -> None:
36
+ """Best-effort terminate a child process AND all of its descendants.
37
+
38
+ change: fix-mcp-subprocess-stdin-deadlock. A plain ``proc.kill()`` reaps only the
39
+ direct child; a surviving grandchild (e.g. the uv-trampoline launcher's real
40
+ interpreter) keeps the captured stdout/stderr pipes open and hangs the post-kill
41
+ ``communicate()``. On Windows we ``taskkill /F /T`` the PID tree; on POSIX we
42
+ ``killpg`` (the child is spawned with ``start_new_session=True``). Never raises.
43
+ """
44
+ pid = getattr(proc, "pid", None)
45
+ if pid is not None:
46
+ try:
47
+ if os.name == "nt":
48
+ subprocess.run(
49
+ ["taskkill", "/F", "/T", "/PID", str(pid)],
50
+ stdin=subprocess.DEVNULL,
51
+ stdout=subprocess.DEVNULL,
52
+ stderr=subprocess.DEVNULL,
53
+ timeout=10,
54
+ )
55
+ else:
56
+ os.killpg(os.getpgid(pid), signal.SIGKILL)
57
+ except Exception:
58
+ pass # missing taskkill / already-dead / permission — fall through
59
+ # Ensure the direct child is gone regardless.
60
+ try:
61
+ proc.kill()
62
+ except Exception:
63
+ pass
64
+
65
+
34
66
  class SuiteExecutionService:
35
67
  """Service for executing Robot Framework test suites in dry run and normal modes."""
36
68
 
@@ -297,6 +329,12 @@ class SuiteExecutionService:
297
329
  start_time = datetime.now()
298
330
 
299
331
  # Prepare Robot Framework options
332
+ # NOTE: do NOT add --console none here. The dry-run captures RF's console output
333
+ # via a PIPE and the validation parser reads it (there is no output.xml —
334
+ # --output NONE), so suppressing the console would blank suite_info/test_count.
335
+ # The stdin=DEVNULL isolation below (change: fix-mcp-subprocess-stdin-deadlock)
336
+ # is what fixes the Windows deadlock; the captured stdout is a pipe, not an
337
+ # inherited handle, so there is nothing to defend against with --console none.
300
338
  rf_options = ["--dryrun", "--output", "NONE", "--report", "NONE", "--log", "NONE"]
301
339
 
302
340
  # Add validation level options (execution_options may override loglevel)
@@ -325,20 +363,42 @@ class SuiteExecutionService:
325
363
  # write to the underlying stdout fd and bypass contextlib.redirect_stdout).
326
364
  def run_robot_dry():
327
365
  cmd = [sys.executable, "-m", "robot", *rf_options]
366
+ # stdin=DEVNULL: the dry-run child MUST NOT inherit the MCP server's stdin
367
+ # (its JSON-RPC read channel). On Windows an inherited synchronous stdin
368
+ # pipe deadlocks the child's C-runtime stdio init behind the server's
369
+ # pending read → the dry-run hangs the full timeout (change:
370
+ # fix-mcp-subprocess-stdin-deadlock). Popen (not subprocess.run) so a
371
+ # timeout can reap the whole tree BEFORE draining the pipes.
372
+ popen_kwargs = dict(
373
+ stdin=subprocess.DEVNULL,
374
+ stdout=subprocess.PIPE,
375
+ stderr=subprocess.PIPE,
376
+ text=True,
377
+ encoding="utf-8",
378
+ errors="replace",
379
+ )
380
+ if os.name != "nt":
381
+ popen_kwargs["start_new_session"] = True # own group for killpg
328
382
  try:
329
- proc = subprocess.run(
330
- cmd,
331
- capture_output=True,
332
- text=True,
333
- encoding="utf-8",
334
- errors="replace",
335
- timeout=timeout_s,
336
- )
337
- return proc.returncode, proc.stdout or "", proc.stderr or ""
383
+ proc = subprocess.Popen(cmd, **popen_kwargs)
384
+ except Exception as e:
385
+ logger.error(f"Robot Framework dry run error: {e}")
386
+ return 252, "", str(e)
387
+ try:
388
+ stdout, stderr = proc.communicate(timeout=timeout_s)
389
+ return proc.returncode, stdout or "", stderr or ""
338
390
  except subprocess.TimeoutExpired:
391
+ # Reap the whole tree so an orphaned grandchild cannot keep the
392
+ # capture pipes open and hang the drain below.
393
+ _kill_process_tree(proc)
394
+ try:
395
+ proc.communicate(timeout=5)
396
+ except Exception:
397
+ pass
339
398
  raise
340
399
  except Exception as e:
341
400
  logger.error(f"Robot Framework dry run error: {e}")
401
+ _kill_process_tree(proc)
342
402
  return 252, "", str(e)
343
403
 
344
404
  loop = asyncio.get_event_loop()
@@ -97,9 +97,12 @@ class LibraryAvailabilityChecker:
97
97
  def check_pip_package_installed(self, package_name: str) -> bool:
98
98
  """Check if a pip package is installed using pip list."""
99
99
  try:
100
+ # stdin=DEVNULL: never inherit the MCP server's stdin — an inherited
101
+ # synchronous stdin pipe deadlocks this child on Windows behind the server's
102
+ # pending JSON-RPC read (change: fix-mcp-subprocess-stdin-deadlock).
100
103
  result = subprocess.run([
101
104
  sys.executable, '-m', 'pip', 'list', '--format=freeze'
102
- ], capture_output=True, text=True, timeout=10)
105
+ ], capture_output=True, text=True, timeout=10, stdin=subprocess.DEVNULL)
103
106
 
104
107
  if result.returncode == 0:
105
108
  installed_packages = result.stdout.lower()
File without changes
File without changes