mainsequence 3.19.2__tar.gz → 3.19.3__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 (186) hide show
  1. {mainsequence-3.19.2 → mainsequence-3.19.3}/PKG-INFO +2 -2
  2. {mainsequence-3.19.2 → mainsequence-3.19.3}/README.md +1 -1
  3. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +350 -36
  4. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/api.py +13 -7
  5. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/cli.py +55 -49
  6. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/models_tdag.py +50 -18
  7. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/PKG-INFO +2 -2
  8. {mainsequence-3.19.2 → mainsequence-3.19.3}/pyproject.toml +1 -1
  9. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_cli.py +71 -10
  10. {mainsequence-3.19.2 → mainsequence-3.19.3}/LICENSE +0 -0
  11. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/AGENTS.md +0 -0
  12. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
  13. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  14. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
  15. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
  16. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
  17. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
  18. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
  19. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
  20. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
  21. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  22. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
  23. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/data_publishing/simple_tables/SKILL.md +0 -0
  24. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  25. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/maintenance/local_journal/SKILL.md +0 -0
  26. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/markets_platform/assets_and_translation/SKILL.md +0 -0
  27. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/markets_platform/instruments_and_pricing/SKILL.md +0 -0
  28. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/markets_platform/virtualfundbuilder/SKILL.md +0 -0
  29. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
  30. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  31. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
  32. {mainsequence-3.19.2 → mainsequence-3.19.3}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
  33. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/__init__.py +0 -0
  34. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/__main__.py +0 -0
  35. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/bootstrap.py +0 -0
  36. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/__init__.py +0 -0
  37. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/browser_auth.py +0 -0
  38. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/config.py +0 -0
  39. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/docker_utils.py +0 -0
  40. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/doctor.py +0 -0
  41. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/local_ops.py +0 -0
  42. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/model_filters.py +0 -0
  43. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/project_status.py +0 -0
  44. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/pydantic_cli.py +0 -0
  45. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/sdk_utils.py +0 -0
  46. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/ssh_utils.py +0 -0
  47. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/cli/ui.py +0 -0
  48. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/__init__.py +0 -0
  49. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/agent_runtime_models.py +0 -0
  50. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/base.py +0 -0
  51. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/client.py +0 -0
  52. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/__init__.py +0 -0
  53. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/app_component.py +0 -0
  54. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/connections.py +0 -0
  55. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/data_models.py +0 -0
  56. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/workspace.py +0 -0
  57. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
  58. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  59. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
  60. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/data_sources_interfaces/timescale.py +0 -0
  61. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/exceptions.py +0 -0
  62. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/fastapi/__init__.py +0 -0
  63. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/fastapi/auth.py +0 -0
  64. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/models_helpers.py +0 -0
  65. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/models_simple_tables.py +0 -0
  66. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/models_user.py +0 -0
  67. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/models_vam.py +0 -0
  68. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/client/utils.py +0 -0
  69. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/compute_validation.py +0 -0
  70. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/__init__.py +0 -0
  71. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/__init__.py +0 -0
  72. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/config.toml +0 -0
  73. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/favicon.png +0 -0
  74. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/image_1_base64.txt +0 -0
  75. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/image_2_base64.txt +0 -0
  76. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/image_3_base64.txt +0 -0
  77. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/image_4_base64.txt +0 -0
  78. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/image_5_base64.txt +0 -0
  79. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/assets/logo.png +0 -0
  80. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/components/__init__.py +0 -0
  81. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/components/asset_select.py +0 -0
  82. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/components/date_settings.py +0 -0
  83. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/components/logged_user.py +0 -0
  84. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/core/__init__.py +0 -0
  85. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/core/theme.py +0 -0
  86. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/instruments/__init__.py +0 -0
  87. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/instruments/streamlit_form_factory.py +0 -0
  88. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/pages/__init__.py +0 -0
  89. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/dashboards/streamlit/scaffold.py +0 -0
  90. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/defaults.py +0 -0
  91. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instrumentation/__init__.py +0 -0
  92. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instrumentation/utils.py +0 -0
  93. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/__init__.py +0 -0
  94. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/data_interface/__init__.py +0 -0
  95. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/data_interface/data_interface.py +0 -0
  96. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/__init__.py +0 -0
  97. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/base_instrument.py +0 -0
  98. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/bond.py +0 -0
  99. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/callability.py +0 -0
  100. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/interest_rate_swap.py +0 -0
  101. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/json_codec.py +0 -0
  102. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/position.py +0 -0
  103. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/instruments/ql_fields.py +0 -0
  104. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/interest_rates/__init__.py +0 -0
  105. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/interest_rates/etl/__init__.py +0 -0
  106. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/interest_rates/etl/curve_codec.py +0 -0
  107. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/interest_rates/etl/nodes.py +0 -0
  108. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/interest_rates/etl/registry.py +0 -0
  109. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/pricing_models/__init__.py +0 -0
  110. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/pricing_models/bond_pricer.py +0 -0
  111. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/pricing_models/indices.py +0 -0
  112. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/pricing_models/indices_builders.py +0 -0
  113. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/pricing_models/swap_pricer.py +0 -0
  114. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/settings.py +0 -0
  115. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/instruments/utils.py +0 -0
  116. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/logconf.py +0 -0
  117. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/runtime_flags.py +0 -0
  118. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/__init__.py +0 -0
  119. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/__main__.py +0 -0
  120. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/base_persist_managers.py +0 -0
  121. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/config.py +0 -0
  122. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/configuration_models.py +0 -0
  123. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/__init__.py +0 -0
  124. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/build_operations.py +0 -0
  125. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/data_nodes.py +0 -0
  126. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/filters.py +0 -0
  127. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/models.py +0 -0
  128. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/namespacing.py +0 -0
  129. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/persist_managers.py +0 -0
  130. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/run_operations.py +0 -0
  131. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/data_nodes/utils.py +0 -0
  132. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/filters.py +0 -0
  133. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/future_registry.py +0 -0
  134. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/pydantic_metadata.py +0 -0
  135. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/__init__.py +0 -0
  136. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/filters.py +0 -0
  137. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/models.py +0 -0
  138. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/persist_managers.py +0 -0
  139. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/schema.py +0 -0
  140. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/simple_tables/table_nodes.py +0 -0
  141. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/tdag/utils.py +0 -0
  142. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/__init__.py +0 -0
  143. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/__init__.py +0 -0
  144. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/__init__.py +0 -0
  145. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/external_weights.py +0 -0
  146. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/intraday_trend.py +0 -0
  147. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/market_cap.py +0 -0
  148. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/mock_signal.py +0 -0
  149. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/data_nodes/portfolio_replicator.py +0 -0
  150. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/prices/__init__.py +0 -0
  151. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/prices/data_nodes.py +0 -0
  152. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/prices/utils.py +0 -0
  153. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/__init__.py +0 -0
  154. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/rebalance_strategies.py +0 -0
  155. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/enums.py +0 -0
  156. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/models.py +0 -0
  157. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/portfolio_nodes.py +0 -0
  158. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/resource_factory/__init__.py +0 -0
  159. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/resource_factory/rebalance_factory.py +0 -0
  160. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/resource_factory/signal_factory.py +0 -0
  161. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence/virtualfundbuilder/utils.py +0 -0
  162. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/SOURCES.txt +0 -0
  163. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/dependency_links.txt +0 -0
  164. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/entry_points.txt +0 -0
  165. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/requires.txt +0 -0
  166. {mainsequence-3.19.2 → mainsequence-3.19.3}/mainsequence.egg-info/top_level.txt +0 -0
  167. {mainsequence-3.19.2 → mainsequence-3.19.3}/setup.cfg +0 -0
  168. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_auth_precedence.py +0 -0
  169. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_build_operations_hashing.py +0 -0
  170. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_cli_browser_auth.py +0 -0
  171. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_client.py +0 -0
  172. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_command_center_app_component_models.py +0 -0
  173. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_command_center_data_models.py +0 -0
  174. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_command_center_models.py +0 -0
  175. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_dependency_extras.py +0 -0
  176. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_filter_normalization.py +0 -0
  177. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_instruments.py +0 -0
  178. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_logconf.py +0 -0
  179. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_logged_user_components.py +0 -0
  180. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_models_user_request_bound_auth.py +0 -0
  181. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_pod_project_resolution.py +0 -0
  182. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_project_batch_jobs_from_file.py +0 -0
  183. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_run_configuration.py +0 -0
  184. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_simple_tables_configuration_hashing.py +0 -0
  185. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_simple_tables_persistence.py +0 -0
  186. {mainsequence-3.19.2 → mainsequence-3.19.3}/tests/test_workspace_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 3.19.2
3
+ Version: 3.19.3
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License: MainSequence GmbH SDK License Agreement
@@ -89,7 +89,7 @@ Requires-Dist: playwright; extra == "workspace-snapshots"
89
89
  Dynamic: license-file
90
90
 
91
91
  <p align="center">
92
- <img src="https://main-sequence.app/static/media/logos/MS_logo_long_black.png" alt="Main Sequence Logo" width="500"/>
92
+ <img src="https://www.main-sequence.io/images/logos/MS_logo_long_black.png" alt="Main Sequence Logo" width="500"/>
93
93
  </p>
94
94
 
95
95
  # Main Sequence Python SDK
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://main-sequence.app/static/media/logos/MS_logo_long_black.png" alt="Main Sequence Logo" width="500"/>
2
+ <img src="https://www.main-sequence.io/images/logos/MS_logo_long_black.png" alt="Main Sequence Logo" width="500"/>
3
3
  </p>
4
4
 
5
5
  # Main Sequence Python SDK
@@ -104,6 +104,92 @@ Think in terms of these objects:
104
104
  - saved widget or saved group:
105
105
  import-layer snapshot/template, not a live linked widget instance inside the workspace
106
106
 
107
+ ## Workspace JSON Model
108
+
109
+ Workspace JSON is the durable workspace definition. It is not a raw frontend state dump and it is
110
+ not a loaded runtime snapshot.
111
+
112
+ Portable export artifacts may use a wrapper:
113
+
114
+ ```json
115
+ {
116
+ "schema": "mainsequence.workspace",
117
+ "version": 1,
118
+ "exportedAt": "2026-05-07T00:00:00.000Z",
119
+ "workspace": {
120
+ "id": "workspace-example",
121
+ "title": "Example Workspace",
122
+ "description": "User-scoped workspace managed in Command Center.",
123
+ "type": "workspace",
124
+ "labels": [],
125
+ "category": "Custom",
126
+ "source": "user",
127
+ "layoutKind": "custom",
128
+ "grid": { "columns": 48, "rowHeight": 15, "gap": 8 },
129
+ "controls": {
130
+ "enabled": true,
131
+ "timeRange": {
132
+ "enabled": true,
133
+ "defaultRange": "24h",
134
+ "options": ["15m", "1h", "6h", "24h", "7d", "30d", "90d"]
135
+ },
136
+ "refresh": {
137
+ "enabled": true,
138
+ "defaultIntervalMs": 300000,
139
+ "intervals": [null, 30000, 60000, 300000, 600000, 3600000]
140
+ },
141
+ "actions": { "enabled": true, "share": false, "view": true }
142
+ },
143
+ "widgets": []
144
+ }
145
+ }
146
+ ```
147
+
148
+ Use the wrapper for portable artifacts. For direct workspace update commands, pass the writable
149
+ workspace payload shape expected by that command, not an arbitrary wrapper, unless the command
150
+ explicitly documents wrapper support.
151
+
152
+ Durable workspace JSON owns:
153
+
154
+ - workspace metadata, labels, category, source, layout kind, grid, and shared controls
155
+ - mounted widget instances and ordering
156
+ - widget `props`, `layout`, `position`, `bindings`, `managedBy`, `presentation`, and `row.children`
157
+ - connection/query configuration on source widgets when the source widget contract requires it
158
+
159
+ Durable workspace JSON does not own:
160
+
161
+ - current user-selected control values when the platform separates user state
162
+ - runtime/view state when the platform separates user state
163
+ - credentials, provider URLs, native socket details, or backend route fragments
164
+ - compiled or public runtime metadata generated by the platform
165
+
166
+ ## Widget Instance Shape
167
+
168
+ Each mounted widget instance should resolve to this shape:
169
+
170
+ ```json
171
+ {
172
+ "id": "unique-instance-id",
173
+ "widgetId": "registered-widget-type-id",
174
+ "title": "Optional title",
175
+ "props": {},
176
+ "bindings": {},
177
+ "layout": { "cols": 12, "rows": 8 },
178
+ "position": { "x": 0, "y": 0 }
179
+ }
180
+ ```
181
+
182
+ Important fields:
183
+
184
+ - `id`: unique mounted instance id inside the workspace
185
+ - `widgetId`: registered widget type id, not a saved-widget id and not a mounted instance id
186
+ - `props`: durable widget configuration
187
+ - `runtimeState`: optional current runtime/view state, not durable source configuration
188
+ - `bindings`: target-owned graph edges from this widget's input ports to upstream output ports
189
+ - `managedBy`: marks hidden managed source widgets
190
+ - `presentation`: placement, rail visibility, chrome, and exposed field behavior
191
+ - `row.children`: nested widgets inside a row/container widget
192
+
107
193
  ## Inputs This Skill Needs
108
194
 
109
195
  Before writing or mutating a workspace, collect or infer:
@@ -286,27 +372,133 @@ If the payload shape is not defined by those sources and cannot be verified, sto
286
372
 
287
373
  ### 3.1 Resolve connection-backed data before mounting consumers
288
374
 
289
- Before mounting table, chart, statistic, curve, or similar data consumers:
375
+ Connections are backend-owned data resources. Workspace consumers should not store connection
376
+ details directly unless their registered widget contract explicitly supports embedded managed source
377
+ props.
290
378
 
291
- 1. identify the source Connection Query widget
292
- 2. verify the selected connection instance exists and is usable
293
- 3. verify the connection type and `queryModelId`
294
- 4. verify the typed query payload
295
- 5. verify the published output contract
296
- 6. add a Tabular Transform widget if analytical reshaping is required
297
- 7. bind consumers to the source or transform `dataset` output
379
+ Prefer explicit source widgets:
298
380
 
299
- Do not store endpoint URLs, credentials, backend route fragments, provider ids, or mutable
300
- connection display labels as authoritative widget props.
381
+ - `connection-query` for request/response datasets
382
+ - `connection-stream-query` for streaming or incremental paths
383
+ - `tabular-transform` when analytical reshaping is needed before presentation
301
384
 
302
- Generic tabular consumers must receive `core.tabular_frame@v1`. If the upstream API or connection
303
- returns raw arrays, paginated JSON, nested provider payloads, or other ad hoc records, normalize
304
- through an Adapter from API connection first, then use an explicit transform when analytical
305
- reshaping is still required.
385
+ One source widget can feed several consumers. Reuse one source when the same query drives several
386
+ tables, charts, statistics, curves, or agent contexts.
306
387
 
307
- When a project API or AppComponent legitimately returns a full canonical frame, ground the contract
308
- against `mainsequence.client.command_center.data_models.TabularFrameResponse`. Source-specific
309
- runtime details belong in `source.context`, not top-level widget payload fields.
388
+ Before mounting table, chart, statistic, curve, or similar data consumers:
389
+
390
+ 1. identify the source widget
391
+ 2. verify the selected connection instance exists and is usable
392
+ 3. verify `connectionRef.id` is real and backend-owned
393
+ 4. verify `connectionRef.typeId` matches the connection type
394
+ 5. verify `queryModelId` matches `query.kind`
395
+ 6. verify the typed query payload matches the selected connection type and query model
396
+ 7. verify the published output contract
397
+ 8. add a Tabular Transform widget if analytical reshaping is required
398
+ 9. bind consumers to the source or transform output through target-owned `bindings`
399
+
400
+ Do not store credentials, provider URLs, native route fragments, backend route fragments, provider
401
+ ids, or mutable connection display labels as authoritative widget props.
402
+
403
+ Request/response source props:
404
+
405
+ ```json
406
+ {
407
+ "connectionRef": { "id": 123, "typeId": "mainsequence.simple-table" },
408
+ "queryModelId": "simple-table-sql",
409
+ "query": {
410
+ "kind": "simple-table-sql",
411
+ "sql": "select * from {{simple_table}} limit 500"
412
+ },
413
+ "timeRangeMode": "dashboard",
414
+ "variables": {},
415
+ "maxRows": 500
416
+ }
417
+ ```
418
+
419
+ Incremental request/response props:
420
+
421
+ ```json
422
+ {
423
+ "incrementalRefreshMode": "incremental",
424
+ "incrementalTimeField": "timestamp",
425
+ "incrementalMergeKeyFields": ["symbol", "timestamp"],
426
+ "incrementalOverlapMs": 60000,
427
+ "incrementalRetentionMs": 86400000,
428
+ "incrementalDedupePolicy": "latest"
429
+ }
430
+ ```
431
+
432
+ Stream source props:
433
+
434
+ ```json
435
+ {
436
+ "connectionRef": { "id": 123, "typeId": "binance.market-data" },
437
+ "queryModelId": "ticker-stream",
438
+ "query": {
439
+ "kind": "ticker-stream",
440
+ "symbols": ["BTCUSDT", "ETHUSDT"]
441
+ },
442
+ "timeRangeMode": "none",
443
+ "mergeKeyFields": ["symbol"],
444
+ "retentionMaxRows": 1000
445
+ }
446
+ ```
447
+
448
+ Connection source rules:
449
+
450
+ - use stream widgets only when the query model advertises stream support
451
+ - configure retention and merge keys explicitly when the consumer expects bounded live state
452
+ - incremental refresh requires a time-range-aware query model and stable time and identity columns
453
+ - `incrementalTimeField` must exist in the returned frame
454
+ - `incrementalMergeKeyFields` must identify stable rows
455
+ - generic tabular consumers must receive `core.tabular_frame@v1`
456
+ - if the upstream connection returns raw arrays, paginated JSON, nested provider payloads, or other
457
+ ad hoc records, normalize through an Adapter from API connection first, then use an explicit
458
+ transform when analytical reshaping is still required
459
+ - when a project API or AppComponent legitimately returns a full canonical frame, ground the
460
+ contract against `mainsequence.client.command_center.data_models.TabularFrameResponse`
461
+ - source-specific runtime details belong in `source.context`, not top-level widget payload fields
462
+
463
+ ### 3.2 Historical and incremental lanes
464
+
465
+ Modern tabular consumers use explicit role inputs:
466
+
467
+ - `seedData`: retained baseline or historical dataset
468
+ - `liveUpdates`: incremental publication lane
469
+
470
+ Source outputs:
471
+
472
+ - `connection-query.dataset`: retained `core.tabular_frame@v1` frame for historical consumers
473
+ - `connection-query.updates`: incremental output when incremental refresh is active
474
+ - `connection-stream-query.dataset`: retained compatibility frame
475
+ - `connection-stream-query.updates`: seed/update publication stream
476
+
477
+ Canonical binding shape:
478
+
479
+ ```json
480
+ "bindings": {
481
+ "seedData": {
482
+ "sourceWidgetId": "historical-source",
483
+ "sourceOutputId": "dataset"
484
+ },
485
+ "liveUpdates": {
486
+ "sourceWidgetId": "stream-source",
487
+ "sourceOutputId": "updates"
488
+ }
489
+ }
490
+ ```
491
+
492
+ Rules:
493
+
494
+ - historical/request-response data uses `dataset -> seedData`
495
+ - live or incremental data uses `updates -> liveUpdates`
496
+ - `sourceData` is legacy or compatibility input; use it only when the widget contract requires it
497
+ - do not send stream `dataset` to `liveUpdates`
498
+ - do not send request/response `dataset` to `liveUpdates`
499
+ - generic tabular consumers must receive `core.tabular_frame@v1`
500
+ - raw arrays, paginated JSON, or nested provider payloads must be normalized before reaching generic
501
+ consumers
310
502
 
311
503
  ### 4. Shared workspace state and current-user state are different
312
504
 
@@ -389,26 +581,51 @@ Prefer:
389
581
  Bindings are canonical instance-level graph edges. They live on the target widget instance in
390
582
  `bindings`, not in `props`, and not in widget-type metadata.
391
583
 
392
- One binding is always defined as:
584
+ One binding is always:
393
585
 
394
- - target widget instance + target input id
395
- - source widget instance + source output id
396
- - optional ordered transform steps
586
+ ```text
587
+ source widget output port -> target widget input port
588
+ ```
397
589
 
398
590
  Persisted shape:
399
591
 
400
592
  - `bindings[inputId] = WidgetPortBinding`
401
593
  - `bindings[inputId] = WidgetPortBinding[]` when the target input declares `cardinality: "many"`
402
594
 
403
- A `WidgetPortBinding` minimally contains:
595
+ Minimal `WidgetPortBinding`:
404
596
 
405
- - `sourceWidgetId`
406
- - `sourceOutputId`
407
- - optional `transformSteps`
597
+ ```json
598
+ {
599
+ "sourceWidgetId": "prices-source",
600
+ "sourceOutputId": "dataset"
601
+ }
602
+ ```
408
603
 
409
- Treat `transformSteps` as canonical. Legacy `transformId`, `transformPath`, and
604
+ Binding with transform steps:
605
+
606
+ ```json
607
+ {
608
+ "sourceWidgetId": "source-widget",
609
+ "sourceOutputId": "agent-context",
610
+ "transformSteps": [
611
+ { "id": "extract-path", "path": ["summary"], "contractId": "core.value.string@v1" }
612
+ ]
613
+ }
614
+ ```
615
+
616
+ Treat ordered `transformSteps` as canonical. Legacy `transformId`, `transformPath`, and
410
617
  `transformContractId` may still appear only as backward-compatible mirrors for older persisted
411
- workspaces.
618
+ workspaces. Do not author those legacy fields in new workspace JSON.
619
+
620
+ Supported lightweight transform steps:
621
+
622
+ - `select-array-item`
623
+ - `extract-path`
624
+
625
+ Binding transforms are only for selecting one array item or extracting a nested field before
626
+ compatibility is evaluated. Do not use binding transforms for analytical reshaping. Use a
627
+ `tabular-transform` widget for projection, aggregate, pivot, unpivot, filtering, joining, or other
628
+ visible data operations.
412
629
 
413
630
  Do not describe bindings loosely as “widget A uses widget B”. In this platform, bindings are always
414
631
  port-to-port:
@@ -424,17 +641,16 @@ Resolve bindings from the target widget outward:
424
641
  2. For each target input, record:
425
642
  - `inputId`
426
643
  - accepted contracts
644
+ - `acceptedOutputIds`
427
645
  - `required`
428
646
  - `cardinality`
429
647
  - `effects`
430
648
  3. Choose a source widget instance that actually publishes the required output id.
431
- 4. If the source output is structured JSON or an array, resolve binding transforms before contract
649
+ 4. Validate the source output id against `acceptedOutputIds` when the target input declares it.
650
+ 5. If the source output is structured JSON or an array, resolve binding transforms before contract
432
651
  validation.
433
- - supported transform steps:
434
- - `select-array-item`
435
- - `extract-path`
436
- 5. Validate the transformed contract against the target input `accepts`.
437
- 6. Treat the binding as usable only when the resolved status is `valid`.
652
+ 6. Validate the transformed contract against the target input `accepts`.
653
+ 7. Treat the binding as usable only when the resolved status is `valid`.
438
654
 
439
655
  A binding can exist in workspace JSON and still be unusable at runtime. The runtime may resolve a
440
656
  binding as:
@@ -461,6 +677,10 @@ Runtime and persistence rules:
461
677
  - binding changes clear that target widget's `runtimeState`
462
678
  - the widget settings `Bindings` tab and the workspace graph editor edit the same canonical binding model
463
679
  - for `cardinality: "many"` inputs, preserve order and store an array of bindings for that input id
680
+ - for `cardinality: "one"` inputs, store a single binding object, not an array
681
+ - do not bind a widget to itself
682
+ - graph/editor interactions may be dragged in either visual direction, but persisted JSON is always
683
+ normalized back to target-owned bindings
464
684
 
465
685
  Dynamic-IO rule:
466
686
 
@@ -471,6 +691,10 @@ Dynamic-IO rule:
471
691
  Concrete examples:
472
692
 
473
693
  - a Connection Query widget publishes `dataset`; a Tabular Transform widget can consume and republish `dataset`
694
+ - modern tabular consumers use explicit role inputs:
695
+ - historical/request-response data binds `dataset -> seedData`
696
+ - live or incremental data binds `updates -> liveUpdates`
697
+ - legacy `sourceData` should appear only when the widget contract still requires it
474
698
  - `main-sequence-ai-agent-terminal` accepts one input with `cardinality: "many"`, so several
475
699
  upstream widget contexts can feed one terminal
476
700
  - widgets that implement `buildAgentSnapshot(...)` may also publish a synthetic `agent-context`
@@ -483,16 +707,85 @@ Review rule:
483
707
  - target input id
484
708
  - source widget instance id
485
709
  - source output id
710
+ - accepted output id constraint, if any
486
711
  - transform steps, if any
487
712
  - final resolved contract
488
713
  - final resolved status
489
714
 
715
+ ## Managed Connection Sources
716
+
717
+ Some consumers support embedded connection authoring. Treat this as UI convenience, not a shortcut
718
+ around the source-widget model.
719
+
720
+ The persisted model still has:
721
+
722
+ - a visible owner widget, for example `graph`
723
+ - a hidden source widget, either `connection-query` or `connection-stream-query`
724
+ - `managedBy: { "ownerInstanceId": "<owner-id>", "role": "embedded-connection-source" }` on the hidden source widget
725
+ - a normal binding from the owner input to the hidden source output
726
+
727
+ Owner widget:
728
+
729
+ ```json
730
+ {
731
+ "id": "graph-1",
732
+ "widgetId": "graph",
733
+ "props": {
734
+ "graphSourceMode": "connection",
735
+ "embeddedConnectionQuery": {
736
+ "connectionRef": { "id": 123, "typeId": "mainsequence.simple-table" },
737
+ "queryModelId": "simple-table-sql",
738
+ "query": { "kind": "simple-table-sql", "sql": "select * from {{simple_table}}" }
739
+ }
740
+ },
741
+ "bindings": {
742
+ "seedData": {
743
+ "sourceWidgetId": "graph-1-source",
744
+ "sourceOutputId": "dataset"
745
+ }
746
+ }
747
+ }
748
+ ```
749
+
750
+ Hidden source widget:
751
+
752
+ ```json
753
+ {
754
+ "id": "graph-1-source",
755
+ "widgetId": "connection-query",
756
+ "title": "Graph Source",
757
+ "props": {
758
+ "connectionRef": { "id": 123, "typeId": "mainsequence.simple-table" },
759
+ "queryModelId": "simple-table-sql",
760
+ "query": { "kind": "simple-table-sql", "sql": "select * from {{simple_table}}" }
761
+ },
762
+ "managedBy": {
763
+ "ownerInstanceId": "graph-1",
764
+ "role": "embedded-connection-source"
765
+ },
766
+ "presentation": {
767
+ "placementMode": "sidebar",
768
+ "railVisibility": "hidden"
769
+ }
770
+ }
771
+ ```
772
+
773
+ Managed stream sources bind hidden source `updates` to owner `liveUpdates`.
774
+
775
+ Rules:
776
+
777
+ - keep owner props, hidden source props, `managedBy`, and bindings aligned
778
+ - do not leave orphan hidden source widgets
779
+ - do not point `managedBy.ownerInstanceId` at a missing owner
780
+ - prefer explicit visible source widgets when they make the workspace easier to inspect or reuse
781
+
490
782
 
491
783
  ## Review Rules
492
784
 
493
785
  When reviewing a workspace task, look for:
494
786
 
495
787
  - guessed widget payloads
788
+ - guessed input ids or output ids
496
789
  - widget work that skipped CLI registry verification
497
790
  - widget work that skipped SDK client model review when one exists
498
791
  - unknown or unverified `widgetId` values
@@ -500,12 +793,21 @@ When reviewing a workspace task, look for:
500
793
  - workspace mutation attempted without first exporting the current workspace JSON
501
794
  - widget payloads changed without saving versioned JSON drafts under `workspaces/widgets/`
502
795
  - workspace-wide rewrites for one-widget changes
503
- - shared state mixed incorrectly with current-user runtime state
796
+ - current-user runtime state mixed into durable workspace JSON accidentally
504
797
  - runtime ownership violations such as consumer widgets inventing canonical fetch paths
505
798
  - unresolved external resource ids
506
- - connection-backed consumers missing a source or transform `dataset` binding
799
+ - connection-backed consumers missing a source widget or required transform widget
507
800
  - generic tabular consumers bound to raw JSON instead of `core.tabular_frame@v1`
508
801
  - full canonical tabular payloads that drift from `TabularFrameResponse`
802
+ - bindings authored in `props` instead of `widget.bindings`
803
+ - bindings placed on the source widget instead of the target widget
804
+ - bindings that ignore `acceptedOutputIds`
805
+ - `dataset -> liveUpdates`
806
+ - stream `dataset` used for live data instead of stream `updates`
807
+ - stream or incremental outputs wired to the wrong role input
808
+ - binding transforms used for analytical reshaping instead of a transform widget
809
+ - hidden managed source widgets missing their owner widget
810
+ - stale `managedBy.ownerInstanceId` values
509
811
  - widget trees using structures not supported by the Main Sequence repository source models
510
812
 
511
813
  ## Validation Checklist
@@ -523,13 +825,25 @@ Do not claim success until you have checked:
523
825
  - versioned workspace/widget JSON files were preserved pending user acceptance
524
826
  - widget detail was reviewed for `widgetVersion`, configuration, runtime, IO, capabilities, agent hints, and examples
525
827
  - the relevant SDK client model was reviewed when one exists
526
- - connection-backed source widgets have verified connection instance, connection type, query model, typed query payload, and output contract
828
+ - every source widget has a valid connection ref, query model id, typed query payload, and output contract
829
+ - every `query.kind` matches `queryModelId`
527
830
  - generic tabular consumers receive `core.tabular_frame@v1`
831
+ - every binding references an existing source widget and output id
832
+ - every binding targets an existing input id
833
+ - every binding matches the target input contract
834
+ - every binding respects `acceptedOutputIds` when declared
835
+ - `cardinality: "many"` bindings preserve order as arrays
836
+ - `cardinality: "one"` bindings are single binding objects
837
+ - historical/request-response data uses `dataset -> seedData` when the widget exposes role inputs
838
+ - live or incremental data uses `updates -> liveUpdates` when the widget exposes role inputs
528
839
  - full canonical tabular frames match `TabularFrameResponse`
529
840
  - widget ids and widget instance ids are correct
530
841
  - any mounted widget that depends on a project API points to a FastAPI project resource that already exists
531
842
  - any mounted widget that depends on a project API points to a FastAPI `ResourceRelease` that already exists
532
843
  - local payload shape was reconciled against the verified widget id, widget-detail contract, and SDK model
844
+ - managed sources have valid `managedBy.ownerInstanceId` values
845
+ - owner widgets and hidden managed source widgets agree on connection/query props
846
+ - no credentials, native URLs, or backend route fragments are embedded in workspace JSON
533
847
  - the chosen mutation mode is correct:
534
848
  - full workspace update
535
849
  - widget-scoped mutation
@@ -591,27 +591,33 @@ def get_projects() -> list[dict]:
591
591
  return data.get("results") or []
592
592
 
593
593
 
594
- def list_org_project_names(
594
+ def search_projects(
595
+ q: str,
595
596
  *,
597
+ limit: int = 20,
596
598
  timeout: int | None = None,
597
- ) -> list[str]:
599
+ ) -> list[dict[str, Any]]:
598
600
  """
599
- List organization-visible project names via SDK client model.
601
+ Search projects visible to the authenticated user via SDK client model.
600
602
 
601
603
  Single source of truth:
602
- - delegates payload parsing to `Project.get_org_project_names()`
604
+ - delegates payload parsing to `Project.quick_search()`
603
605
  """
604
606
  try:
605
607
  payload = _run_sdk_model_operation(
606
608
  module_name="mainsequence.client.models_tdag",
607
609
  class_name="Project",
608
- operation=lambda ClientProject: ClientProject.get_org_project_names(timeout=timeout),
610
+ operation=lambda ClientProject: ClientProject.quick_search(
611
+ q=q,
612
+ limit=limit,
613
+ timeout=timeout,
614
+ ),
609
615
  )
610
- return [str(item) for item in list(payload or [])]
616
+ return [_sdk_object_to_dict(item) for item in list(payload or [])]
611
617
  except Exception as e:
612
618
  if isinstance(e, (ApiError, NotLoggedIn)):
613
619
  raise
614
- raise ApiError(f"Organization project names fetch failed: {e}") from e
620
+ raise ApiError(f"Project search failed: {e}") from e
615
621
 
616
622
 
617
623
  def validate_project_name(
@@ -137,7 +137,6 @@ from .api import (
137
137
  list_github_organizations,
138
138
  list_market_asset_translation_tables,
139
139
  list_market_portfolios,
140
- list_org_project_names,
141
140
  list_organization_teams,
142
141
  list_project_base_images,
143
142
  list_project_images,
@@ -188,6 +187,7 @@ from .api import (
188
187
  run_project_job,
189
188
  safe_slug,
190
189
  schedule_batch_project_jobs,
190
+ search_projects,
191
191
  semantic_search_agents,
192
192
  start_agent_new_session,
193
193
  sync_project_after_commit,
@@ -2570,54 +2570,6 @@ def user_show():
2570
2570
  )
2571
2571
 
2572
2572
 
2573
- @organization.command("project-names")
2574
- def organization_project_names_cmd(
2575
- timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
2576
- ):
2577
- """
2578
- List project names visible to the authenticated user's organization.
2579
-
2580
- Uses SDK client `Project.get_org_project_names()` as the single source of truth.
2581
-
2582
- Examples
2583
- --------
2584
- ```bash
2585
- mainsequence organization project-names
2586
- mainsequence organization project-names --timeout 60
2587
- ```
2588
- """
2589
- _require_login()
2590
-
2591
- try:
2592
- project_names = list_org_project_names(timeout=timeout)
2593
- except ApiError as e:
2594
- error(f"Organization project names fetch failed: {e}")
2595
- raise typer.Exit(1) from e
2596
-
2597
- if _emit_json(project_names):
2598
- return
2599
-
2600
- if project_names:
2601
- print_table(
2602
- "Organization Project Names",
2603
- ["Project Name"],
2604
- [[project_name] for project_name in project_names],
2605
- )
2606
- else:
2607
- info("No organization-visible project names.")
2608
- info(f"Total organization-visible project names: {len(project_names)}")
2609
-
2610
-
2611
- @organization.command("project_names", hidden=True)
2612
- def organization_project_names_alias_cmd(
2613
- timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
2614
- ):
2615
- """
2616
- Backward-compatible alias for `mainsequence organization project-names`.
2617
- """
2618
- organization_project_names_cmd(timeout=timeout)
2619
-
2620
-
2621
2573
  @organization.command("github-organizations")
2622
2574
  def organization_github_organizations_cmd():
2623
2575
  """
@@ -7945,6 +7897,60 @@ def project_validate_name_cmd(
7945
7897
  raise typer.Exit(1)
7946
7898
 
7947
7899
 
7900
+ @project.command("search")
7901
+ def project_search_cmd(
7902
+ q: str = typer.Argument(..., help="Project search query. Minimum 3 characters."),
7903
+ limit: int = typer.Option(20, "--limit", min=1, max=100, help="Maximum number of matches to return."),
7904
+ timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
7905
+ ):
7906
+ """
7907
+ Search projects visible to the authenticated user.
7908
+
7909
+ Uses SDK client `Project.quick_search()` as the single source of truth.
7910
+
7911
+ Examples
7912
+ --------
7913
+ ```bash
7914
+ mainsequence project search "tutorial"
7915
+ mainsequence project search "rates" --limit 10
7916
+ mainsequence project search "161"
7917
+ ```
7918
+ """
7919
+ _require_login()
7920
+
7921
+ normalized_query = (q or "").strip()
7922
+ if len(normalized_query) < 3:
7923
+ error("Project search failed: Query must contain at least 3 characters.")
7924
+ raise typer.Exit(1)
7925
+
7926
+ try:
7927
+ projects = search_projects(normalized_query, limit=limit, timeout=timeout)
7928
+ except ApiError as e:
7929
+ error(f"Project search failed: {e}")
7930
+ raise typer.Exit(1) from e
7931
+
7932
+ if _emit_json(projects):
7933
+ return
7934
+
7935
+ if projects:
7936
+ print_table(
7937
+ "Project Search Results",
7938
+ ["ID", "Project Name", "Repository Branch", "Cluster ID"],
7939
+ [
7940
+ [
7941
+ str(project.get("id") or "-"),
7942
+ str(project.get("project_name") or "-"),
7943
+ str(project.get("repository_branch") or "-"),
7944
+ str(project.get("cluster_id") or "-"),
7945
+ ]
7946
+ for project in projects
7947
+ ],
7948
+ )
7949
+ else:
7950
+ info("No projects matched the search.")
7951
+ info(f'Project search matches for "{normalized_query}": {len(projects)}')
7952
+
7953
+
7948
7954
  @project.command("validate_name", hidden=True)
7949
7955
  def project_validate_name_alias_cmd(
7950
7956
  project_name: str = typer.Argument(..., help="Project name to validate."),