cmpnd 0.28.0__tar.gz → 0.29.0__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 (351) hide show
  1. {cmpnd-0.28.0 → cmpnd-0.29.0}/PKG-INFO +1 -1
  2. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/admin.py +25 -4
  3. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/cli.md +9 -0
  4. {cmpnd-0.28.0 → cmpnd-0.29.0}/pyproject.toml +1 -1
  5. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_admin.py +43 -1
  6. {cmpnd-0.28.0 → cmpnd-0.29.0}/uv.lock +1 -1
  7. {cmpnd-0.28.0 → cmpnd-0.29.0}/.gitignore +0 -0
  8. {cmpnd-0.28.0 → cmpnd-0.29.0}/AGENTS.md +0 -0
  9. {cmpnd-0.28.0 → cmpnd-0.29.0}/CLAUDE.md +0 -0
  10. {cmpnd-0.28.0 → cmpnd-0.29.0}/README.md +0 -0
  11. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/__init__.py +0 -0
  12. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_assessments.py +0 -0
  13. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_authored_import.py +0 -0
  14. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_deployments.py +0 -0
  15. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_exporter_pool.py +0 -0
  16. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_gepa_patch.py +0 -0
  17. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_http.py +0 -0
  18. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_program_patch.py +0 -0
  19. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_rlm_patch.py +0 -0
  20. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_runtime_tools.py +0 -0
  21. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_timespec.py +0 -0
  22. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_traces.py +0 -0
  23. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/_valsets.py +0 -0
  24. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/authored.py +0 -0
  25. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/callback.py +0 -0
  26. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/__init__.py +0 -0
  27. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/api_client.py +0 -0
  28. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/__init__.py +0 -0
  29. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/assessments.py +0 -0
  30. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/auth.py +0 -0
  31. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/datasets.py +0 -0
  32. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/deployments.py +0 -0
  33. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/evals.py +0 -0
  34. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/login.py +0 -0
  35. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/optimizations.py +0 -0
  36. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/org.py +0 -0
  37. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/programs.py +0 -0
  38. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  39. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/signatures.py +0 -0
  40. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  41. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/top.py +0 -0
  42. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/traces.py +0 -0
  43. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/commands/valsets.py +0 -0
  44. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/credentials.py +0 -0
  45. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/deprecation.py +0 -0
  46. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/pagination.py +0 -0
  47. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/shell.py +0 -0
  48. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/trace_render.py +0 -0
  49. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/tree_help.py +0 -0
  50. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/cli/verbs.py +0 -0
  51. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/client.py +0 -0
  52. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/configuration.py +0 -0
  53. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/context.py +0 -0
  54. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/dataset_sync.py +0 -0
  55. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/datasets.py +0 -0
  56. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/decorators.py +0 -0
  57. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/deployment.py +0 -0
  58. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/deployment_metadata.py +0 -0
  59. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/eval_handler.py +0 -0
  60. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/execution.py +0 -0
  61. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/exporter.py +0 -0
  62. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/exporter_http.py +0 -0
  63. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/helpers.py +0 -0
  64. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/identity.py +0 -0
  65. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/imaging.py +0 -0
  66. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/__init__.py +0 -0
  67. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/decode.py +0 -0
  68. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/encode.py +0 -0
  69. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/hash.py +0 -0
  70. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/program.py +0 -0
  71. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/reflection.py +0 -0
  72. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/types.py +0 -0
  73. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/ir/xxh64.py +0 -0
  74. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/lm_configuration.py +0 -0
  75. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/mcp_servers.py +0 -0
  76. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/models.py +0 -0
  77. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimization.py +0 -0
  78. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimizers/__init__.py +0 -0
  79. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimizers/gepa.py +0 -0
  80. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  81. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimizers/resume.py +0 -0
  82. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/optimizers/tracker.py +0 -0
  83. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/packaging.py +0 -0
  84. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/references.py +0 -0
  85. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/retry.py +0 -0
  86. {cmpnd-0.28.0 → cmpnd-0.29.0}/cmpnd/traces.py +0 -0
  87. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/2026-04-02-code-review.md +0 -0
  88. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/client.md +0 -0
  89. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/custom-proposer.md +0 -0
  90. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  91. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  92. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/reading-traces.md +0 -0
  93. {cmpnd-0.28.0 → cmpnd-0.29.0}/docs/sdk-instrumentation.md +0 -0
  94. {cmpnd-0.28.0 → cmpnd-0.29.0}/examples/generalizing_proposer.py +0 -0
  95. {cmpnd-0.28.0 → cmpnd-0.29.0}/examples/local_ollama.py +0 -0
  96. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/LINEAGE.md +0 -0
  97. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/README.md +0 -0
  98. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  99. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  100. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  101. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  102. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/py.typed +0 -0
  103. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  104. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/cmpnd_ingest/retry.py +0 -0
  105. {cmpnd-0.28.0 → cmpnd-0.29.0}/ingest/pyproject.toml +0 -0
  106. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/audit-sdist.sh +0 -0
  107. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/capture_review_run.py +0 -0
  108. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/check_release_artifacts.py +0 -0
  109. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/fixtures/review_run.json.gz +0 -0
  110. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/gepa_resume_bug.py +0 -0
  111. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/release-stress.sh +0 -0
  112. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/require_version_bump.py +0 -0
  113. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/seed_review_run.py +0 -0
  114. {cmpnd-0.28.0 → cmpnd-0.29.0}/scripts/test-in-linux.sh +0 -0
  115. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/__init__.pyi +0 -0
  116. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  117. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  118. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/utils/__init__.pyi +0 -0
  119. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/utils/callback.pyi +0 -0
  120. {cmpnd-0.28.0 → cmpnd-0.29.0}/stubs/dspy/utils/dummies.pyi +0 -0
  121. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/__init__.py +0 -0
  122. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_deployment_signature_helpers.py +0 -0
  123. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_exporter_helpers.py +0 -0
  124. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_fake_clock.py +0 -0
  125. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_identity_helpers.py +0 -0
  126. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_resolve_refs.py +0 -0
  127. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/_traced_run.py +0 -0
  128. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/conftest.py +0 -0
  129. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/__init__.py +0 -0
  130. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/committee_task.py +0 -0
  131. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/conftest.py +0 -0
  132. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  133. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  134. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/fake_lm.py +0 -0
  135. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/helpers.py +0 -0
  136. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/target_capabilities.py +0 -0
  137. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_assessments_cli.py +0 -0
  138. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_capture_prompts.py +0 -0
  139. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_composite_module.py +0 -0
  140. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  141. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_deploy_execute.py +0 -0
  142. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_deploy_programs.py +0 -0
  143. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_edge_cases.py +0 -0
  144. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_example_hash.py +0 -0
  145. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_gepa_optimization.py +0 -0
  146. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_interpreter_spans.py +0 -0
  147. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_lm_accuracy.py +0 -0
  148. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_module_tracing.py +0 -0
  149. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimization_lineage.py +0 -0
  150. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  151. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimize_failures.py +0 -0
  152. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimize_loop.py +0 -0
  153. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  154. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  155. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_parallel_export.py +0 -0
  156. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_project_attribution.py +0 -0
  157. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_react_tool_spans.py +0 -0
  158. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_save_load.py +0 -0
  159. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_trace_structure.py +0 -0
  160. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_traces_read.py +0 -0
  161. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_user_attribution.py +0 -0
  162. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/e2e/test_valsets_cli.py +0 -0
  163. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  164. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  165. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  166. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  167. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  168. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  169. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  170. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  171. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  172. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/10_react.json +0 -0
  173. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/11_refine.json +0 -0
  174. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/12_retrieve.json +0 -0
  175. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/13_knn.json +0 -0
  176. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/14_parallel.json +0 -0
  177. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/identity_vectors/README.md +0 -0
  178. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/ingest_conformance.py +0 -0
  179. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/__init__.py +0 -0
  180. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/authored_optimize/judge.py +0 -0
  181. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  182. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/conftest.py +0 -0
  183. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  184. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/hosted_optimize_probe.py +0 -0
  185. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/optimization_run_probe.py +0 -0
  186. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  187. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/test_logs_renders_traces.py +0 -0
  188. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/test_optimization_run.py +0 -0
  189. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/test_optimizing_progress.py +0 -0
  190. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/integration/test_unhappy_path.py +0 -0
  191. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/__init__.py +0 -0
  192. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/__main__.py +0 -0
  193. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/drain.py +0 -0
  194. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/ingest.py +0 -0
  195. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/latency_transport.py +0 -0
  196. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/rlm_shape.py +0 -0
  197. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/rlm_size_report.py +0 -0
  198. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/sweep.py +0 -0
  199. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/test_rlm_shape.py +0 -0
  200. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/load/test_rlm_size_report.py +0 -0
  201. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/__init__.py +0 -0
  202. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/conftest.py +0 -0
  203. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/seed_parity.py +0 -0
  204. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_auth.py +0 -0
  205. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_datasets.py +0 -0
  206. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_deployments.py +0 -0
  207. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_evals.py +0 -0
  208. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_health.py +0 -0
  209. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_modules.py +0 -0
  210. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_optimizations.py +0 -0
  211. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_programs.py +0 -0
  212. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_signatures.py +0 -0
  213. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_trace_streaming.py +0 -0
  214. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/parity/test_traces.py +0 -0
  215. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/span_reference_fixture.py +0 -0
  216. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/__init__.py +0 -0
  217. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/_provider.py +0 -0
  218. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/_readiness.py +0 -0
  219. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/_reliability.py +0 -0
  220. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/_result.py +0 -0
  221. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/mint_bedrock_token.py +0 -0
  222. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_deploy_programs.py +0 -0
  223. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_multi_client_stress.py +0 -0
  224. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_optimize_client_committee.py +0 -0
  225. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_optimize_loop.py +0 -0
  226. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_optimize_loop_wasm.py +0 -0
  227. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_optimize_stress.py +0 -0
  228. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_provider_roles.py +0 -0
  229. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_readiness.py +0 -0
  230. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_real_provider_twins.py +0 -0
  231. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_reliability.py +0 -0
  232. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_reliability_classify.py +0 -0
  233. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_rlm_wasm.py +0 -0
  234. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/stress/test_trace_search.py +0 -0
  235. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_adapter_reentrancy.py +0 -0
  236. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_assessments_api.py +0 -0
  237. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_authored.py +0 -0
  238. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_authored_bundle_collisions.py +0 -0
  239. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_authored_metric_contract.py +0 -0
  240. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_authored_named_models.py +0 -0
  241. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_authored_optimize.py +0 -0
  242. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_callback.py +0 -0
  243. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_candidate_lineage.py +0 -0
  244. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/__init__.py +0 -0
  245. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/conftest.py +0 -0
  246. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_api_client.py +0 -0
  247. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_assessments.py +0 -0
  248. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_auth.py +0 -0
  249. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_credentials.py +0 -0
  250. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_datasets.py +0 -0
  251. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_deployments.py +0 -0
  252. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_evals.py +0 -0
  253. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_login.py +0 -0
  254. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_main.py +0 -0
  255. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_optimizations.py +0 -0
  256. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_org.py +0 -0
  257. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_pagination.py +0 -0
  258. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_parity.py +0 -0
  259. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_programs.py +0 -0
  260. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_provider_credentials.py +0 -0
  261. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_schema_sample.py +0 -0
  262. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_shell.py +0 -0
  263. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_signatures.py +0 -0
  264. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_tool_servers.py +0 -0
  265. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_top.py +0 -0
  266. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_traces.py +0 -0
  267. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  268. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_tree_help.py +0 -0
  269. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cli/test_valsets.py +0 -0
  270. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_client.py +0 -0
  271. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_clustering/__init__.py +0 -0
  272. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_clustering/conftest.py +0 -0
  273. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_clustering/test_edge_cases.py +0 -0
  274. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  275. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_clustering/test_type_conversion.py +0 -0
  276. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_cmp551_grouping_identity.py +0 -0
  277. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_configuration.py +0 -0
  278. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_context.py +0 -0
  279. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_context_propagation.py +0 -0
  280. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_dataset_polling.py +0 -0
  281. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_dataset_sync.py +0 -0
  282. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_datasets.py +0 -0
  283. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_decorators.py +0 -0
  284. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_deploy.py +0 -0
  285. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_deploy_mcp_tool_references.py +0 -0
  286. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_deployment_metadata.py +0 -0
  287. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_deployments_read.py +0 -0
  288. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_eval.py +0 -0
  289. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_eval_example_attribution.py +0 -0
  290. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_eval_start.py +0 -0
  291. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_eval_trace_grouping.py +0 -0
  292. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_exception_paths.py +0 -0
  293. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_execute.py +0 -0
  294. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_exporter.py +0 -0
  295. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_exporter_queue.py +0 -0
  296. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_exporter_real.py +0 -0
  297. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_fake_lm.py +0 -0
  298. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_gepa_callback.py +0 -0
  299. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_gepa_integration.py +0 -0
  300. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_gepa_resume.py +0 -0
  301. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_identity.py +0 -0
  302. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_imaging.py +0 -0
  303. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_import_weight.py +0 -0
  304. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_ingest_conformance.py +0 -0
  305. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_ingest_second_producer.py +0 -0
  306. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_integration.py +0 -0
  307. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_interpreter_callback.py +0 -0
  308. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_ir_encoder_properties.py +0 -0
  309. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_ir_golden_vectors.py +0 -0
  310. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_ir_roundtrip.py +0 -0
  311. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_lm_configuration.py +0 -0
  312. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_lm_usage_shapes.py +0 -0
  313. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_mcp_tools.py +0 -0
  314. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_models.py +0 -0
  315. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimization_progress.py +0 -0
  316. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimization_start.py +0 -0
  317. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize.py +0 -0
  318. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_budget.py +0 -0
  319. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_lift.py +0 -0
  320. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_lms.py +0 -0
  321. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_proposer.py +0 -0
  322. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_reflection_lm.py +0 -0
  323. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_optimize_terminal_failure.py +0 -0
  324. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_packaging.py +0 -0
  325. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_packaging_callable_source.py +0 -0
  326. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_packaging_mcp_tools.py +0 -0
  327. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_packaging_program_source.py +0 -0
  328. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_poll_until.py +0 -0
  329. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_program_lineage_persist.py +0 -0
  330. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_project_payload.py +0 -0
  331. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_reflector_properties.py +0 -0
  332. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_reflector_smoke.py +0 -0
  333. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_release_stress_script.py +0 -0
  334. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_repro_reactv2_bugs.py +0 -0
  335. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_require_version_bump.py +0 -0
  336. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_retry.py +0 -0
  337. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_reversible_failures.py +0 -0
  338. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_rlm_patch.py +0 -0
  339. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_runtime_tools.py +0 -0
  340. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_schemas.py +0 -0
  341. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_seed_review_run.py +0 -0
  342. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_span_references.py +0 -0
  343. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_span_sent_once.py +0 -0
  344. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_trace_render.py +0 -0
  345. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_traces_read.py +0 -0
  346. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_tracked_gepa.py +0 -0
  347. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_tracker_enrich.py +0 -0
  348. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_truncation.py +0 -0
  349. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_valsets_api.py +0 -0
  350. {cmpnd-0.28.0 → cmpnd-0.29.0}/tests/test_xxh64.py +0 -0
  351. {cmpnd-0.28.0 → cmpnd-0.29.0}/todo.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.28.0
3
+ Version: 0.29.0
4
4
  Summary: DSPy observability and deployment SDK for cmpnd
5
5
  Project-URL: Homepage, https://cmpnd.ai
6
6
  Author-email: cmpnd <hello@cmpnd.ai>
@@ -1,8 +1,9 @@
1
1
  """Platform-operator commands, hidden behind CMPND_CLI_ADMIN=1.
2
2
 
3
- `cmpnd admin org create|set-owner|list|show|set-limit|set-github-login|elect-owner`
3
+ `cmpnd admin org create|invite|set-owner|list|show|set-limit|set-github-login|elect-owner`
4
4
  is the closed-beta org bootstrap and steward surface:
5
- stand up a shared org with its GitHub auto-join key, anoint its first owner,
5
+ stand up a shared org with its GitHub auto-join key, prepare one for a customer
6
+ with a pre-approved owner invite (``create --owner-email``), anoint its first owner,
6
7
  adjust its member cap or GitHub link, and grant ownership from the election
7
8
  queue. `cmpnd admin user …` is the operator's user-lifecycle surface (list,
8
9
  inspect, create, approve/reject the pending-signup queue, promote/demote admin,
@@ -42,8 +43,19 @@ def _register_org(sub: _SubParsersAction[ArgumentParser]) -> None:
42
43
  default="",
43
44
  help="GitHub org login for OAuth auto-join (optional)",
44
45
  )
46
+ create.add_argument(
47
+ "--owner-email",
48
+ dest="owner_email",
49
+ default="",
50
+ help="Prepare the org for this customer: mail them a pre-approved owner invite (optional)",
51
+ )
45
52
  create.set_defaults(func=handle_org_create)
46
53
 
54
+ invite_owner = osub.add_parser("invite", help="Mail a pre-approved owner invite into an org that has no owner")
55
+ invite_owner.add_argument("org_id", help="Organization id")
56
+ invite_owner.add_argument("email", help="The customer's email")
57
+ invite_owner.set_defaults(func=handle_org_invite_owner)
58
+
47
59
  set_owner = osub.add_parser("set-owner", help="Make an existing user the org's owner")
48
60
  set_owner.add_argument("org_id", help="Organization id")
49
61
  set_owner.add_argument("email", help="Owner email (must already be a provisioned user)")
@@ -169,9 +181,18 @@ def _register_feature_flags(sub: _SubParsersAction[ArgumentParser]) -> None:
169
181
 
170
182
 
171
183
  def handle_org_create(client: api_client.ApiClient, args: Any) -> Any:
184
+ # With --owner-email the server marks the org operator-seeded and mails the
185
+ # customer a pre-approved owner invite; redeeming it hands the org over.
186
+ body = {"name": args.name, "github_login": args.github_login}
187
+ if args.owner_email:
188
+ body["owner_email"] = args.owner_email
189
+ return client.post("/api/v1/admin/organizations", json=body)
190
+
191
+
192
+ def handle_org_invite_owner(client: api_client.ApiClient, args: Any) -> Any:
172
193
  return client.post(
173
- "/api/v1/admin/organizations",
174
- json={"name": args.name, "github_login": args.github_login},
194
+ f"/api/v1/admin/organizations/{args.org_id}/owner-invite",
195
+ json={"email": args.email},
175
196
  )
176
197
 
177
198
 
@@ -413,3 +413,12 @@ not store, so the endpoint's existing key stays in place. Plain
413
413
  `cmpnd login` never carries admin scopes, so an operator's everyday key has
414
414
  ordinary privilege. `--admin` does not combine with `--with-token`, because a
415
415
  pasted key keeps the scopes it was minted with.
416
+
417
+ `cmpnd admin org create NAME --owner-email EMAIL` prepares an org for a
418
+ customer. The server creates the org, marks it operator-seeded, and mails EMAIL
419
+ a pre-approved owner invite. The response carries the invite link as
420
+ `owner_invite.url` in case the email does not arrive. When the customer redeems
421
+ the link they become the org's owner, with no approval step, and `cmpnd admin
422
+ org show` reports the org handed off (`seed.handoff_pending: false`). `cmpnd
423
+ admin org invite ORG_ID EMAIL` does the same for an existing org that has
424
+ no owner, and the server refuses an org that already has one.
@@ -5,7 +5,7 @@ name = "cmpnd"
5
5
  # it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
6
6
  # hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
7
7
  # this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
8
- version = "0.28.0"
8
+ version = "0.29.0"
9
9
  description = "DSPy observability and deployment SDK for cmpnd"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
@@ -10,13 +10,55 @@ from cmpnd.cli.commands import admin
10
10
  class TestAdminOrg:
11
11
  def test_create_posts_name_and_github_login(self, mock_client):
12
12
  mock_client.post.return_value = {"id": "o_1", "name": "Acme", "github_login": "acme"}
13
- result = admin.handle_org_create(mock_client, Namespace(name="Acme", github_login="acme"))
13
+ result = admin.handle_org_create(mock_client, Namespace(name="Acme", github_login="acme", owner_email=""))
14
14
  mock_client.post.assert_called_once_with(
15
15
  "/api/v1/admin/organizations",
16
16
  json={"name": "Acme", "github_login": "acme"},
17
17
  )
18
18
  assert result["github_login"] == "acme"
19
19
 
20
+ def test_create_without_owner_email_sends_no_owner_email(self, mock_client):
21
+ mock_client.post.return_value = {"id": "o_1"}
22
+ admin.handle_org_create(mock_client, Namespace(name="Acme", github_login="", owner_email=""))
23
+ mock_client.post.assert_called_once_with(
24
+ "/api/v1/admin/organizations",
25
+ json={"name": "Acme", "github_login": ""},
26
+ )
27
+
28
+ def test_create_with_owner_email_prepares_the_org_for_its_customer(self, mock_client):
29
+ mock_client.post.return_value = {
30
+ "id": "o_1",
31
+ "owner_invite": {"role": "owner", "email": "founder@acme.com", "url": "https://x/auth/invite/t"},
32
+ }
33
+ result = admin.handle_org_create(
34
+ mock_client, Namespace(name="Acme", github_login="", owner_email="founder@acme.com")
35
+ )
36
+ mock_client.post.assert_called_once_with(
37
+ "/api/v1/admin/organizations",
38
+ json={"name": "Acme", "github_login": "", "owner_email": "founder@acme.com"},
39
+ )
40
+ assert result["owner_invite"]["role"] == "owner"
41
+
42
+ def test_invite_owner_posts_email(self, mock_client):
43
+ mock_client.post.return_value = {"role": "owner", "email": "founder@acme.com"}
44
+ result = admin.handle_org_invite_owner(mock_client, Namespace(org_id="o_1", email="founder@acme.com"))
45
+ mock_client.post.assert_called_once_with(
46
+ "/api/v1/admin/organizations/o_1/owner-invite",
47
+ json={"email": "founder@acme.com"},
48
+ )
49
+ assert result["role"] == "owner"
50
+
51
+ def test_create_parser_accepts_owner_email(self):
52
+ from argparse import ArgumentParser
53
+
54
+ parser = ArgumentParser()
55
+ admin.register(parser.add_subparsers())
56
+ args = parser.parse_args(["admin", "org", "create", "Acme", "--owner-email", "founder@acme.com"])
57
+ assert args.owner_email == "founder@acme.com"
58
+ assert args.func is admin.handle_org_create
59
+ args = parser.parse_args(["admin", "org", "invite", "o_1", "founder@acme.com"])
60
+ assert args.func is admin.handle_org_invite_owner
61
+
20
62
  def test_set_owner_posts_and_confirms(self, mock_client):
21
63
  mock_client.post.return_value = None # 204 No Content
22
64
  result = admin.handle_org_set_owner(mock_client, Namespace(org_id="o_1", email="owner@acme.com"))
@@ -496,7 +496,7 @@ wheels = [
496
496
 
497
497
  [[package]]
498
498
  name = "cmpnd"
499
- version = "0.28.0"
499
+ version = "0.29.0"
500
500
  source = { editable = "." }
501
501
  dependencies = [
502
502
  { name = "dspy" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes