openadapt 1.2.2__tar.gz → 1.2.4__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 (316) hide show
  1. {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/main.yml +8 -1
  2. {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/release-and-publish.yml +18 -0
  3. {openadapt-1.2.2 → openadapt-1.2.4}/CHANGELOG.md +27 -0
  4. {openadapt-1.2.2 → openadapt-1.2.4}/PKG-INFO +1 -1
  5. {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/__init__.py +3 -5
  6. {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/cli.py +58 -16
  7. {openadapt-1.2.2 → openadapt-1.2.4}/pyproject.toml +1 -1
  8. openadapt-1.2.4/tests/test_cli_smoke.py +231 -0
  9. openadapt-1.2.4/tests/test_import_integrity.py +253 -0
  10. {openadapt-1.2.2 → openadapt-1.2.4}/.github/CODEOWNERS +0 -0
  11. {openadapt-1.2.2 → openadapt-1.2.4}/.github/FUNDING.yml +0 -0
  12. {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/bug_form.yml +0 -0
  13. {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  14. {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/new_feature.yml +0 -0
  15. {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/use_case.yml +0 -0
  16. {openadapt-1.2.2 → openadapt-1.2.4}/.github/pull_request_template.md +0 -0
  17. {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/docs.yml +0 -0
  18. {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/notify-docs.yml +0 -0
  19. {openadapt-1.2.2 → openadapt-1.2.4}/.gitignore +0 -0
  20. {openadapt-1.2.2 → openadapt-1.2.4}/CLAUDE.md +0 -0
  21. {openadapt-1.2.2 → openadapt-1.2.4}/CONTRIBUTING.md +0 -0
  22. {openadapt-1.2.2 → openadapt-1.2.4}/LICENSE +0 -0
  23. {openadapt-1.2.2 → openadapt-1.2.4}/README.md +0 -0
  24. {openadapt-1.2.2 → openadapt-1.2.4}/docs/CNAME +0 -0
  25. {openadapt-1.2.2 → openadapt-1.2.4}/docs/DOCS_UPDATE_SUMMARY.md +0 -0
  26. {openadapt-1.2.2 → openadapt-1.2.4}/docs/LEGACY_FREEZE.md +0 -0
  27. {openadapt-1.2.2 → openadapt-1.2.4}/docs/_scripts/README.md +0 -0
  28. {openadapt-1.2.2 → openadapt-1.2.4}/docs/_scripts/generate_docs_screenshots.py +0 -0
  29. {openadapt-1.2.2 → openadapt-1.2.4}/docs/architecture-evolution.md +0 -0
  30. {openadapt-1.2.2 → openadapt-1.2.4}/docs/architecture.md +0 -0
  31. {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/architecture-diagram.png +0 -0
  32. {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_accessibility.png +0 -0
  33. {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_input_monitoring.png +0 -0
  34. {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_permissions_alert.png +0 -0
  35. {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_screen_recording.png +0 -0
  36. {openadapt-1.2.2 → openadapt-1.2.4}/docs/cli.md +0 -0
  37. {openadapt-1.2.2 → openadapt-1.2.4}/docs/contributing.md +0 -0
  38. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/INDEX.md +0 -0
  39. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/landing-page-strategy.md +0 -0
  40. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/openadapt-tray.md +0 -0
  41. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/production-execution-design.md +0 -0
  42. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/repo-rename-analysis.md +0 -0
  43. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/telemetry-design.md +0 -0
  44. {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/tray-logging.md +0 -0
  45. {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/installation.md +0 -0
  46. {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/permissions.md +0 -0
  47. {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/quickstart.md +0 -0
  48. {openadapt-1.2.2 → openadapt-1.2.4}/docs/index.md +0 -0
  49. {openadapt-1.2.2 → openadapt-1.2.4}/docs/legacy/freeze.md +0 -0
  50. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/capture.md +0 -0
  51. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/evals.md +0 -0
  52. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/grounding.md +0 -0
  53. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/index.md +0 -0
  54. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/ml.md +0 -0
  55. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/privacy.md +0 -0
  56. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/retrieval.md +0 -0
  57. {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/viewer.md +0 -0
  58. {openadapt-1.2.2 → openadapt-1.2.4}/docs/permissions-macos.md +0 -0
  59. {openadapt-1.2.2 → openadapt-1.2.4}/docs/publication-roadmap.md +0 -0
  60. {openadapt-1.2.2 → openadapt-1.2.4}/docs/roadmap-priorities.md +0 -0
  61. {openadapt-1.2.2 → openadapt-1.2.4}/examples/capture_train_eval.py +0 -0
  62. {openadapt-1.2.2 → openadapt-1.2.4}/examples/demo_retrieval_augmented.py +0 -0
  63. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/.flake8 +0 -0
  64. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/.pre-commit-config.yaml +0 -0
  65. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/CHANGELOG.md +0 -0
  66. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/CONTRIBUTING.md +0 -0
  67. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/README.md +0 -0
  68. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/SETUP.md +0 -0
  69. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/fixtures.sql +0 -0
  70. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_accessibility.png +0 -0
  71. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_input_monitoring.png +0 -0
  72. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_permissions_alert.png +0 -0
  73. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_screen_recording.png +0 -0
  74. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/visualize.png +0 -0
  75. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/get_version.py +0 -0
  76. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/macos.sh +0 -0
  77. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/test_app_run_macos.sh +0 -0
  78. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/test_app_run_windows.bat +0 -0
  79. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/upload_release_artifacts.sh +0 -0
  80. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/background.js +0 -0
  81. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/content.js +0 -0
  82. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/icons/logo.png +0 -0
  83. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/manifest.json +0 -0
  84. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/.env.example +0 -0
  85. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/README.md +0 -0
  86. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/.dockerignore +0 -0
  87. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/Dockerfile +0 -0
  88. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/client.py +0 -0
  89. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/deploy.py +0 -0
  90. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/pyproject.toml +0 -0
  91. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/describe_actions.py +0 -0
  92. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/fastsamsom.py +0 -0
  93. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/gpt4o_seg.py +0 -0
  94. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/handle_similar_segments.py +0 -0
  95. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/imagesimilarity.py +0 -0
  96. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/install/install_openadapt.ps1 +0 -0
  97. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/install/install_openadapt.sh +0 -0
  98. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/__init__.py +0 -0
  99. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/__init__.py +0 -0
  100. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/prompt.py +0 -0
  101. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/replicate.py +0 -0
  102. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/som.py +0 -0
  103. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/ultralytics.py +0 -0
  104. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/README +0 -0
  105. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/context_loader.py +0 -0
  106. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/env.py +0 -0
  107. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/script.py.mako +0 -0
  108. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/104d4a614d95_add_performancestat.py +0 -0
  109. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/186316d4f3ca_add_scrubbed_columns.py +0 -0
  110. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/20f9c2afb42c_rename_input_event_to_action_event.py +0 -0
  111. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/2a8a241785f2_add_original_recording_id.py +0 -0
  112. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/30a5ba9d6453_add_active_segment_description_and_.py +0 -0
  113. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/5139d7df38f6_add_recording_task_description.py +0 -0
  114. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py +0 -0
  115. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/57d78d23087a_add_windowevent_state.py +0 -0
  116. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py +0 -0
  117. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/8495f5471e23_add_recording_config.py +0 -0
  118. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/8713b142f5de_add_png_diff_data_and_png_diff_mask_data.py +0 -0
  119. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/87a78a84a8bf_remove_recording_timestamp_fks.py +0 -0
  120. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/98505a067995_add_browserevent_table.py +0 -0
  121. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/98c8851a5321_add_audio_info.py +0 -0
  122. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/a29b537fabe6_add_disabled_field_to_action_event.py +0 -0
  123. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/b206c80f7640_add_recording_inputevent_screenshot_.py +0 -0
  124. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/b2dc41850120_window_window_id.py +0 -0
  125. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/bb25e889ad71_generate_unique_user_id.py +0 -0
  126. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/c24abb5455d3_create_new_recording_fks.py +0 -0
  127. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/d63569e4fb90_actionevent_element_state.py +0 -0
  128. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py +0 -0
  129. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/ec337f277666_datetime_timestamp.py +0 -0
  130. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/f9586c10a561_migrate_data_to_new_fks.py +0 -0
  131. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic.ini +0 -0
  132. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/__init__.py +0 -0
  133. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo.ico +0 -0
  134. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo.png +0 -0
  135. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo_inverted.png +0 -0
  136. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.eslintrc.json +0 -0
  137. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.gitignore +0 -0
  138. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.nvmrc +0 -0
  139. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.prettierrc.json +0 -0
  140. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/README.md +0 -0
  141. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/__init__.py +0 -0
  142. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/action_events.py +0 -0
  143. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/index.py +0 -0
  144. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/recordings.py +0 -0
  145. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/scrubbing.py +0 -0
  146. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/settings.py +0 -0
  147. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api.ts +0 -0
  148. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/favicon.ico +0 -0
  149. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/globals.css +0 -0
  150. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/layout.tsx +0 -0
  151. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/onboarding/page.tsx +0 -0
  152. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/providers.tsx +0 -0
  153. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/RawRecordings.tsx +0 -0
  154. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/ScrubbedRecordings.tsx +0 -0
  155. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/detail/page.tsx +0 -0
  156. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/page.tsx +0 -0
  157. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/routes.ts +0 -0
  158. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/scrubbing/ScrubbingUpdates.tsx +0 -0
  159. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/scrubbing/page.tsx +0 -0
  160. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/(api_keys)/form.tsx +0 -0
  161. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/(api_keys)/page.tsx +0 -0
  162. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/SettingsHeader.tsx +0 -0
  163. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/layout.tsx +0 -0
  164. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/navbar.tsx +0 -0
  165. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/record_and_replay/form.tsx +0 -0
  166. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/record_and_replay/page.tsx +0 -0
  167. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/scrubbing/form.tsx +0 -0
  168. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/scrubbing/page.tsx +0 -0
  169. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/utils.ts +0 -0
  170. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/utils.ts +0 -0
  171. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/assets/logo.png +0 -0
  172. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/ActionEvent.tsx +0 -0
  173. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/ActionEvents.tsx +0 -0
  174. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/RemoveActionEvent.tsx +0 -0
  175. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/Screenshots.tsx +0 -0
  176. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/index.tsx +0 -0
  177. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Navbar/Navbar.tsx +0 -0
  178. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Navbar/index.tsx +0 -0
  179. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx +0 -0
  180. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx +0 -0
  181. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx +0 -0
  182. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/RecordingDetails/RecordingDetails.tsx +0 -0
  183. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/RecordingDetails/index.tsx +0 -0
  184. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Shell/Shell.tsx +0 -0
  185. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Shell/index.tsx +0 -0
  186. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/SimpleTable/SimpleTable.tsx +0 -0
  187. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/SimpleTable/index.tsx +0 -0
  188. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/entrypoint.ps1 +0 -0
  189. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/entrypoint.sh +0 -0
  190. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/index.js +0 -0
  191. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/next.config.js +0 -0
  192. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/package-lock.json +0 -0
  193. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/package.json +0 -0
  194. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/postcss.config.js +0 -0
  195. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/run.py +0 -0
  196. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/tailwind.config.js +0 -0
  197. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/tsconfig.json +0 -0
  198. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/action-event.ts +0 -0
  199. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/recording.ts +0 -0
  200. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/scrubbing.ts +0 -0
  201. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/tray.py +0 -0
  202. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/browser.py +0 -0
  203. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/build.py +0 -0
  204. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/build_utils.py +0 -0
  205. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/cache.py +0 -0
  206. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/__init__.py +0 -0
  207. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/__main__.py +0 -0
  208. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_linux.py +0 -0
  209. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_macos.py +0 -0
  210. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_windows.py +0 -0
  211. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/common.py +0 -0
  212. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/config.defaults.json +0 -0
  213. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/config.py +0 -0
  214. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/__init__.py +0 -0
  215. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/som/__init__.py +0 -0
  216. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/som/visualizer.py +0 -0
  217. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/custom_logger.py +0 -0
  218. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/__init__.py +0 -0
  219. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/crud.py +0 -0
  220. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/db.py +0 -0
  221. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/list.py +0 -0
  222. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/remove.py +0 -0
  223. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/deprecated/app/cards.py +0 -0
  224. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/anthropic.py +0 -0
  225. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/google.py +0 -0
  226. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/openai.py +0 -0
  227. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/entrypoint.py +0 -0
  228. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/error_reporting.py +0 -0
  229. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/events.py +0 -0
  230. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/extensions/synchronized_queue.py +0 -0
  231. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/models.py +0 -0
  232. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/playback.py +0 -0
  233. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/plotting.py +0 -0
  234. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/__init__.py +0 -0
  235. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/base.py +0 -0
  236. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/__init__.py +0 -0
  237. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/aws_comprehend.py +0 -0
  238. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/presidio.py +0 -0
  239. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/private_ai.py +0 -0
  240. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/productivity.py +0 -0
  241. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/apply_replay_instructions.j2 +0 -0
  242. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/describe_recording--segment.j2 +0 -0
  243. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/describe_recording.j2 +0 -0
  244. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/description.j2 +0 -0
  245. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/generate_action_event--segment.j2 +0 -0
  246. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/generate_action_event.j2 +0 -0
  247. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/is_action_complete.j2 +0 -0
  248. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/system.j2 +0 -0
  249. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/record.py +0 -0
  250. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/replay.py +0 -0
  251. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/__init__.py +0 -0
  252. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/reset_db.py +0 -0
  253. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/scrub.py +0 -0
  254. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scrub.py +0 -0
  255. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/share.py +0 -0
  256. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/__init__.py +0 -0
  257. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/download_model.py +0 -0
  258. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/spacy_model_init.py +0 -0
  259. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/start.py +0 -0
  260. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/__init__.py +0 -0
  261. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/base.py +0 -0
  262. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/demo.py +0 -0
  263. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/ascii.py +0 -0
  264. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/huggingface.py +0 -0
  265. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/ocr.py +0 -0
  266. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/openai.py +0 -0
  267. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/sam.py +0 -0
  268. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/summary.py +0 -0
  269. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/naive.py +0 -0
  270. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/segment.py +0 -0
  271. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/stateful.py +0 -0
  272. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/vanilla.py +0 -0
  273. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/visual.py +0 -0
  274. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/visual_browser.py +0 -0
  275. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/utils.py +0 -0
  276. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/video.py +0 -0
  277. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/vision.py +0 -0
  278. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/visualize.py +0 -0
  279. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/__init__.py +0 -0
  280. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_linux.py +0 -0
  281. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_macos.py +0 -0
  282. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_windows.py +0 -0
  283. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/permissions_in_macOS.md +0 -0
  284. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/poetry.lock +0 -0
  285. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/scripts/downloads.py +0 -0
  286. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/scripts/postinstall.py +0 -0
  287. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/setup.py +0 -0
  288. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/calculator.png +0 -0
  289. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/excel.png +0 -0
  290. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/sample_llc_1.pdf +0 -0
  291. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_emr_image.png +0 -0
  292. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_image_redaction_presidio.png +0 -0
  293. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_image_redaction_privateai.png +0 -0
  294. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/conftest.py +0 -0
  295. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_anthropic.py +0 -0
  296. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_google.py +0 -0
  297. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_openai.py +0 -0
  298. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_comprehend_scrub.py +0 -0
  299. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_presidio_scrub.py +0 -0
  300. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_private_ai_scrub.py +0 -0
  301. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/test_providers.py +0 -0
  302. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_browser.py +0 -0
  303. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_crop.py +0 -0
  304. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_crud.py +0 -0
  305. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_events.py +0 -0
  306. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_models.py +0 -0
  307. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_share.py +0 -0
  308. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_summary.py +0 -0
  309. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_utils.py +0 -0
  310. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_video.py +0 -0
  311. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_vision.py +0 -0
  312. {openadapt-1.2.2 → openadapt-1.2.4}/legacy/workflows/release-and-publish.yml +0 -0
  313. {openadapt-1.2.2 → openadapt-1.2.4}/mkdocs.yml +0 -0
  314. {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/config.py +0 -0
  315. {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/version.py +0 -0
  316. {openadapt-1.2.2 → openadapt-1.2.4}/uv.lock +0 -0
@@ -29,7 +29,11 @@ jobs:
29
29
  - name: Install dependencies
30
30
  run: |
31
31
  python -m pip install --upgrade pip
32
- pip install -e ".[dev]"
32
+ # openadapt-ml is installed explicitly so the cross-package
33
+ # seam tests (tests/test_import_integrity.py and the cmd_serve
34
+ # contract in tests/test_cli_smoke.py) run instead of skipping.
35
+ # Issue #999 shipped because this seam was never tested in CI.
36
+ pip install -e ".[dev]" openadapt-ml
33
37
 
34
38
  - name: Lint with ruff
35
39
  run: |
@@ -40,3 +44,6 @@ jobs:
40
44
  run: |
41
45
  python -c "from openadapt.cli import main; print('CLI import OK')"
42
46
  python -c "from openadapt.version import __version__; print(f'Version: {__version__}')"
47
+
48
+ - name: Run tests
49
+ run: pytest tests/ -v
@@ -54,3 +54,21 @@ jobs:
54
54
  poetry config pypi-token.pypi $PYPI_TOKEN
55
55
  poetry build
56
56
  poetry publish --no-interaction --skip-existing
57
+
58
+ # Releases in openadapt-ml failed silently for 3 months (Mar-Jun
59
+ # 2026) while PyPI went stale; see issue #999. Fail loudly instead.
60
+ - name: File issue on release failure
61
+ if: failure()
62
+ env:
63
+ GH_TOKEN: ${{ secrets.ADMIN_TOKEN }}
64
+ run: |
65
+ TITLE="Release workflow failed on main"
66
+ BODY="The release workflow failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
67
+
68
+ Until this is fixed, merged fix/feat commits are NOT being published to PyPI, and users install stale versions."
69
+ EXISTING=$(gh issue list --repo "${{ github.repository }}" --state open --search "in:title \"$TITLE\"" --json number --jq '.[0].number // empty')
70
+ if [ -n "$EXISTING" ]; then
71
+ gh issue comment "$EXISTING" --repo "${{ github.repository }}" --body "$BODY"
72
+ else
73
+ gh issue create --repo "${{ github.repository }}" --title "$TITLE" --body "$BODY"
74
+ fi
@@ -2,6 +2,33 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.2.4 (2026-06-12)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Serve Namespace and lazy-import bugs; add CLI smoke and seam tests
10
+ ([#1002](https://github.com/OpenAdaptAI/OpenAdapt/pull/1002),
11
+ [`7e4d3ce`](https://github.com/OpenAdaptAI/OpenAdapt/commit/7e4d3ce38423ee224d303f204ef9b94025820c11))
12
+
13
+
14
+ ## v1.2.3 (2026-06-12)
15
+
16
+ ### Bug Fixes
17
+
18
+ - Honor --output in serve, clear error for unresolvable configs
19
+ ([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
20
+ [`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
21
+
22
+ - Repair broken openadapt-ml imports in serve and train CLI commands
23
+ ([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
24
+ [`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
25
+
26
+ ### Code Style
27
+
28
+ - Ruff format cli.py ([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
29
+ [`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
30
+
31
+
5
32
  ## v1.2.2 (2026-03-04)
6
33
 
7
34
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openadapt
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: GUI automation with ML - record, train, deploy, evaluate
5
5
  Project-URL: Homepage, https://openadapt.ai
6
6
  Project-URL: Documentation, https://docs.openadapt.ai
@@ -59,11 +59,10 @@ def __getattr__(name: str):
59
59
  return locals()[name]
60
60
 
61
61
  # ML package (heavy - only import if explicitly requested)
62
- if name in ("QwenVLAdapter", "train", "Trainer"):
63
- from openadapt_ml import QwenVLAdapter # noqa: F401
64
- from openadapt_ml.training import Trainer # noqa: F401
62
+ if name == "QwenVLAdapter":
63
+ from openadapt_ml.models.qwen_vl import QwenVLAdapter # noqa: F401
65
64
 
66
- return locals().get(name)
65
+ return QwenVLAdapter
67
66
 
68
67
  # Grounding package (optional)
69
68
  if name in ("Grounder", "OmniGrounder", "GeminiGrounder"):
@@ -115,7 +114,6 @@ __all__ = [
115
114
  "HTMLBuilder",
116
115
  # From ml
117
116
  "QwenVLAdapter",
118
- "Trainer",
119
117
  # From grounding (optional)
120
118
  "Grounder",
121
119
  "OmniGrounder",
@@ -196,23 +196,49 @@ def train_start(
196
196
  try:
197
197
  click.echo("Starting training...")
198
198
  click.echo(f" Capture: {capture}")
199
- click.echo(f" Model: {model}")
200
199
  click.echo(f" Output: {output}")
201
200
 
202
- # Import and run training
203
- from openadapt_ml.scripts.train import train_main
201
+ # Import and run training. The model is determined by the config
202
+ # file; --model is kept for backward compatibility only.
203
+ from openadapt_ml.scripts.train import main as train_main
204
+
205
+ if not config:
206
+ from openadapt_ml.cloud.local import detect_device
207
+
208
+ if "cuda" in detect_device():
209
+ config = "configs/qwen3vl_capture.yaml"
210
+ else:
211
+ config = "configs/qwen3vl_capture_4bit.yaml"
212
+ try:
213
+ from openadapt_ml.cloud.local import resolve_config_path
214
+
215
+ config = str(resolve_config_path(config))
216
+ except ImportError:
217
+ # Older openadapt-ml without resolve_config_path; use as-is.
218
+ pass
219
+
220
+ from pathlib import Path
221
+
222
+ if not Path(config).exists():
223
+ click.echo(f"Error: config not found: {config}", err=True)
224
+ click.echo(
225
+ "Upgrade openadapt-ml so bundled configs resolve, or pass "
226
+ "--config with a path to a training config YAML.",
227
+ err=True,
228
+ )
229
+ sys.exit(1)
230
+ click.echo(f" Config: {config}")
204
231
 
205
232
  train_main(
206
- capture=capture,
207
- model=model,
208
- config=config,
233
+ config_path=config,
234
+ capture_path=capture,
209
235
  output_dir=output,
210
236
  open_dashboard=open,
211
237
  )
212
238
 
213
- except ImportError:
214
- click.echo("Error: openadapt-ml not installed.", err=True)
215
- click.echo("Install with: pip install openadapt-ml", err=True)
239
+ except ImportError as e:
240
+ click.echo(f"Error: failed to import openadapt-ml ({e}).", err=True)
241
+ click.echo('Install with: pip install "openadapt-ml[training]"', err=True)
216
242
  sys.exit(1)
217
243
 
218
244
 
@@ -405,16 +431,32 @@ def serve(port: int, output: str, open: bool):
405
431
  click.echo(f"Starting server on port {port}...")
406
432
  click.echo(f"Serving from: {output}")
407
433
 
408
- from openadapt_ml.cloud.local import serve_dashboard
434
+ import argparse
435
+ from pathlib import Path
409
436
 
410
- serve_dashboard(
411
- output_dir=output,
412
- port=port,
413
- open_browser=open,
437
+ from openadapt_ml.cloud import local as oa_local
438
+
439
+ # cmd_serve resolves the 'current' run against the module-level
440
+ # TRAINING_OUTPUT constant; point it at the requested directory
441
+ # so --output is honored.
442
+ oa_local.TRAINING_OUTPUT = Path(output)
443
+
444
+ sys.exit(
445
+ oa_local.cmd_serve(
446
+ argparse.Namespace(
447
+ port=port,
448
+ benchmark=None,
449
+ no_regenerate=False,
450
+ start_page=None,
451
+ quiet=False,
452
+ open=open,
453
+ )
454
+ )
414
455
  )
415
456
 
416
- except ImportError:
417
- click.echo("Error: openadapt-ml not installed.", err=True)
457
+ except ImportError as e:
458
+ click.echo(f"Error: failed to import openadapt-ml ({e}).", err=True)
459
+ click.echo('Install with: pip install "openadapt-ml[training]"', err=True)
418
460
  sys.exit(1)
419
461
 
420
462
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openadapt"
3
- version = "1.2.2"
3
+ version = "1.2.4"
4
4
  description = "GUI automation with ML - record, train, deploy, evaluate"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -0,0 +1,231 @@
1
+ """CLI smoke and seam-contract tests.
2
+
3
+ Issue #999: `openadapt serve` and `openadapt train start` were broken
4
+ for months while CI stayed green, because cli.py's imports of
5
+ openadapt-ml only execute inside command bodies and the broad
6
+ `except ImportError` handlers reported every failure as
7
+ "openadapt-ml not installed".
8
+
9
+ Three layers of defense here:
10
+
11
+ 1. test_every_command_help — walks the whole Click tree and renders
12
+ --help for every command, so any module-level wiring error fails CI.
13
+ 2. Contract tests — monkeypatch the openadapt-ml entry points and
14
+ assert cli.py calls them the way they're actually shaped today.
15
+ 3. test_cmd_serve_reads_only_provided_args — parses the installed
16
+ openadapt-ml's cmd_serve and asserts every `args.<attr>` it reads is
17
+ provided by cli.py's Namespace, so the seam can't drift silently in
18
+ either direction.
19
+
20
+ The openadapt-ml-dependent tests skip when it isn't installed; CI
21
+ installs it so they always run there.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import ast
27
+ import sys
28
+ from pathlib import Path
29
+
30
+ import click
31
+ import pytest
32
+ from click.testing import CliRunner
33
+
34
+ from openadapt.cli import main as cli_main
35
+
36
+ # Namespace attributes cli.py's serve command provides to cmd_serve.
37
+ # Keep in sync with openadapt/cli.py::serve.
38
+ SERVE_NAMESPACE_ATTRS = {
39
+ "port",
40
+ "benchmark",
41
+ "no_regenerate",
42
+ "start_page",
43
+ "quiet",
44
+ "open",
45
+ }
46
+
47
+
48
+ def _iter_commands(group, prefix=()):
49
+ yield prefix, group
50
+ if isinstance(group, click.Group):
51
+ for name, cmd in group.commands.items():
52
+ yield from _iter_commands(cmd, prefix + (name,))
53
+
54
+
55
+ def test_every_command_help():
56
+ """Render --help for every command in the tree."""
57
+ runner = CliRunner()
58
+ failures = []
59
+ for path, _cmd in _iter_commands(cli_main):
60
+ args = list(path) + ["--help"]
61
+ result = runner.invoke(cli_main, args)
62
+ if result.exit_code != 0:
63
+ failures.append(f"{' '.join(args)!r} exited {result.exit_code}")
64
+ assert not failures, "Commands whose --help failed:\n " + "\n ".join(failures)
65
+
66
+
67
+ def test_version_command():
68
+ runner = CliRunner()
69
+ result = runner.invoke(cli_main, ["version"])
70
+ assert result.exit_code == 0
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Seam contracts with openadapt-ml
75
+ # ---------------------------------------------------------------------------
76
+
77
+
78
+ def _require_openadapt_ml():
79
+ return pytest.importorskip("openadapt_ml", reason="openadapt-ml not installed")
80
+
81
+
82
+ def test_train_start_calls_real_entry_point(monkeypatch, tmp_path):
83
+ """`openadapt train start` must call scripts.train.main with kwargs
84
+ that exist in its signature."""
85
+ _require_openadapt_ml()
86
+ import inspect
87
+
88
+ from openadapt_ml.scripts import train as train_module
89
+
90
+ real_params = set(inspect.signature(train_module.main).parameters)
91
+ calls = []
92
+
93
+ def fake_main(**kwargs):
94
+ unknown = set(kwargs) - real_params
95
+ assert not unknown, (
96
+ f"cli.py passes kwargs {sorted(unknown)} that "
97
+ f"openadapt_ml.scripts.train.main does not accept "
98
+ f"(it takes {sorted(real_params)})"
99
+ )
100
+ calls.append(kwargs)
101
+
102
+ monkeypatch.setattr(train_module, "main", fake_main)
103
+
104
+ capture_dir = tmp_path / "my-capture"
105
+ capture_dir.mkdir()
106
+ config = tmp_path / "config.yaml"
107
+ config.write_text("model:\n name: test\n")
108
+
109
+ runner = CliRunner()
110
+ result = runner.invoke(
111
+ cli_main,
112
+ [
113
+ "train",
114
+ "start",
115
+ "--capture",
116
+ str(capture_dir),
117
+ "--config",
118
+ str(config),
119
+ "--no-open",
120
+ ],
121
+ )
122
+ assert result.exit_code == 0, result.output
123
+ assert len(calls) == 1
124
+ kwargs = calls[0]
125
+ assert kwargs["config_path"] == str(config)
126
+ assert kwargs["capture_path"] == str(capture_dir)
127
+ assert kwargs["open_dashboard"] is False
128
+
129
+
130
+ def test_serve_calls_cmd_serve_with_expected_namespace(monkeypatch):
131
+ """`openadapt serve` must call cmd_serve with the agreed Namespace."""
132
+ _require_openadapt_ml()
133
+ from openadapt_ml.cloud import local as oa_local
134
+
135
+ received = []
136
+
137
+ def fake_cmd_serve(args):
138
+ received.append(args)
139
+ return 0
140
+
141
+ monkeypatch.setattr(oa_local, "cmd_serve", fake_cmd_serve)
142
+
143
+ runner = CliRunner()
144
+ result = runner.invoke(cli_main, ["serve", "--port", "8123", "--no-open"])
145
+ assert result.exit_code == 0, result.output
146
+ assert len(received) == 1
147
+ ns = received[0]
148
+ assert ns.port == 8123
149
+ assert ns.open is False # --no-open passes through to cmd_serve
150
+ for attr in SERVE_NAMESPACE_ATTRS:
151
+ assert hasattr(ns, attr), f"Namespace missing {attr}"
152
+
153
+
154
+ def test_serve_honors_output_directory(monkeypatch, tmp_path):
155
+ """--output must repoint openadapt-ml's TRAINING_OUTPUT."""
156
+ _require_openadapt_ml()
157
+ from openadapt_ml.cloud import local as oa_local
158
+
159
+ monkeypatch.setattr(oa_local, "cmd_serve", lambda args: 0)
160
+
161
+ runner = CliRunner()
162
+ out = tmp_path / "runs"
163
+ result = runner.invoke(cli_main, ["serve", "--output", str(out), "--no-open"])
164
+ assert result.exit_code == 0, result.output
165
+ assert Path(oa_local.TRAINING_OUTPUT) == out
166
+
167
+
168
+ def test_cmd_serve_reads_only_provided_args():
169
+ """Every `args.<attr>` cmd_serve reads must be in cli.py's Namespace.
170
+
171
+ This is the direction the contract can silently drift: openadapt-ml
172
+ adds a new required Namespace attribute and cli.py doesn't provide
173
+ it. Parse the installed cmd_serve and check.
174
+ """
175
+ ml = _require_openadapt_ml()
176
+ local_path = Path(next(iter(ml.__path__))) / "cloud" / "local.py"
177
+ tree = ast.parse(local_path.read_text(encoding="utf-8"))
178
+ cmd_serve = next(
179
+ (
180
+ node
181
+ for node in tree.body
182
+ if isinstance(node, ast.FunctionDef) and node.name == "cmd_serve"
183
+ ),
184
+ None,
185
+ )
186
+ assert cmd_serve is not None, "cmd_serve not found in openadapt-ml"
187
+
188
+ args_param = cmd_serve.args.args[0].arg
189
+ read_attrs = {
190
+ node.attr
191
+ for node in ast.walk(cmd_serve)
192
+ if isinstance(node, ast.Attribute)
193
+ and isinstance(node.value, ast.Name)
194
+ and node.value.id == args_param
195
+ }
196
+ missing = read_attrs - SERVE_NAMESPACE_ATTRS
197
+ assert not missing, (
198
+ f"openadapt-ml's cmd_serve reads args attributes "
199
+ f"{sorted(missing)} that openadapt's serve command does not "
200
+ f"provide; update openadapt/cli.py (and SERVE_NAMESPACE_ATTRS)"
201
+ )
202
+
203
+
204
+ def test_import_error_messages_not_masked(monkeypatch):
205
+ """Internal ImportErrors must surface the real error, not claim
206
+ openadapt-ml isn't installed."""
207
+ _require_openadapt_ml()
208
+
209
+ import builtins
210
+
211
+ real_import = builtins.__import__
212
+
213
+ def broken_import(name, *args, **kwargs):
214
+ if name == "openadapt_ml.cloud" or name.startswith("openadapt_ml.cloud."):
215
+ raise ImportError(
216
+ "cannot import name 'definitely_phantom' from "
217
+ "'openadapt_ml.cloud.local'"
218
+ )
219
+ return real_import(name, *args, **kwargs)
220
+
221
+ monkeypatch.setattr(builtins, "__import__", broken_import)
222
+ monkeypatch.delitem(sys.modules, "openadapt_ml.cloud.local", raising=False)
223
+ monkeypatch.delitem(sys.modules, "openadapt_ml.cloud", raising=False)
224
+
225
+ runner = CliRunner()
226
+ result = runner.invoke(cli_main, ["serve", "--no-open"])
227
+ assert result.exit_code != 0
228
+ assert "definitely_phantom" in result.output, (
229
+ "The underlying ImportError must appear in the CLI output; "
230
+ f"got: {result.output}"
231
+ )