affinity-sdk 0.4.7__tar.gz → 0.9.9__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 (397) hide show
  1. affinity_sdk-0.9.9/.claude-plugin/marketplace.json +26 -0
  2. affinity_sdk-0.9.9/.github/PULL_REQUEST_TEMPLATE/release.md +31 -0
  3. affinity_sdk-0.9.9/.github/workflows/ci.yml +134 -0
  4. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/workflows/docs.yml +9 -5
  5. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/workflows/labels.yml +1 -1
  6. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/workflows/linkcheck.yml +2 -2
  7. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/workflows/openapi-validation.yml +2 -2
  8. affinity_sdk-0.9.9/.github/workflows/plugin-build.yml +106 -0
  9. affinity_sdk-0.9.9/.github/workflows/plugin-release.yml +163 -0
  10. affinity_sdk-0.9.9/.github/workflows/release-detect.yml +135 -0
  11. affinity_sdk-0.9.9/.github/workflows/release.yml +337 -0
  12. affinity_sdk-0.9.9/.github/workflows/version-check.yml +92 -0
  13. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.gitignore +2 -0
  14. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.pre-commit-config.yaml +16 -3
  15. affinity_sdk-0.9.9/CHANGELOG.md +465 -0
  16. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/CONTRIBUTING.md +61 -7
  17. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/PKG-INFO +53 -15
  18. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/README.md +49 -11
  19. affinity_sdk-0.9.9/VERSIONING.md +182 -0
  20. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/__init__.py +2 -0
  21. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/__init__.py +4 -0
  22. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/_entity_files_dump.py +3 -0
  23. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/_v1_parsing.py +28 -3
  24. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/company_cmds.py +601 -562
  25. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/completion_cmd.py +2 -0
  26. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/config_cmds.py +69 -34
  27. affinity_sdk-0.9.9/affinity/cli/commands/entry_cmds.py +33 -0
  28. affinity_sdk-0.9.9/affinity/cli/commands/field_cmds.py +413 -0
  29. affinity_sdk-0.9.9/affinity/cli/commands/interaction_cmds.py +875 -0
  30. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/list_cmds.py +906 -486
  31. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/note_cmds.py +144 -27
  32. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/opportunity_cmds.py +417 -388
  33. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/person_cmds.py +597 -548
  34. affinity_sdk-0.9.9/affinity/cli/commands/query_cmd.py +481 -0
  35. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/relationship_strength_cmds.py +23 -5
  36. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/reminder_cmds.py +184 -39
  37. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/resolve_url_cmd.py +3 -1
  38. affinity_sdk-0.9.9/affinity/cli/commands/session_cmds.py +84 -0
  39. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/task_cmds.py +31 -4
  40. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/version_cmd.py +2 -0
  41. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/whoami_cmd.py +11 -0
  42. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/context.py +33 -3
  43. affinity_sdk-0.9.9/affinity/cli/csv_utils.py +195 -0
  44. affinity_sdk-0.9.9/affinity/cli/date_utils.py +42 -0
  45. affinity_sdk-0.9.9/affinity/cli/decorators.py +77 -0
  46. affinity_sdk-0.9.9/affinity/cli/formatters.py +551 -0
  47. affinity_sdk-0.9.9/affinity/cli/help_json.py +283 -0
  48. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/main.py +94 -17
  49. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/options.py +9 -2
  50. affinity_sdk-0.9.9/affinity/cli/progress.py +183 -0
  51. affinity_sdk-0.9.9/affinity/cli/query/__init__.py +163 -0
  52. affinity_sdk-0.9.9/affinity/cli/query/aggregates.py +357 -0
  53. affinity_sdk-0.9.9/affinity/cli/query/dates.py +194 -0
  54. affinity_sdk-0.9.9/affinity/cli/query/exceptions.py +147 -0
  55. affinity_sdk-0.9.9/affinity/cli/query/executor.py +1977 -0
  56. affinity_sdk-0.9.9/affinity/cli/query/filters.py +700 -0
  57. affinity_sdk-0.9.9/affinity/cli/query/models.py +335 -0
  58. affinity_sdk-0.9.9/affinity/cli/query/output.py +339 -0
  59. affinity_sdk-0.9.9/affinity/cli/query/parser.py +619 -0
  60. affinity_sdk-0.9.9/affinity/cli/query/planner.py +538 -0
  61. affinity_sdk-0.9.9/affinity/cli/query/progress.py +270 -0
  62. affinity_sdk-0.9.9/affinity/cli/query/schema.py +472 -0
  63. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/render.py +440 -45
  64. affinity_sdk-0.9.9/affinity/cli/resolve.py +222 -0
  65. affinity_sdk-0.9.9/affinity/cli/results.py +308 -0
  66. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/runner.py +92 -26
  67. affinity_sdk-0.9.9/affinity/cli/session_cache.py +276 -0
  68. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/client.py +4 -2
  69. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/clients/http.py +1 -1
  70. affinity_sdk-0.9.9/affinity/compare.py +501 -0
  71. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/exceptions.py +22 -0
  72. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/filters.py +425 -33
  73. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/inbound_webhooks.py +7 -0
  74. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/entities.py +5 -0
  75. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/pagination.py +19 -1
  76. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/types.py +42 -6
  77. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/companies.py +103 -9
  78. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/lists.py +314 -63
  79. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/opportunities.py +254 -17
  80. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/persons.py +203 -9
  81. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/v1_only.py +17 -0
  82. affinity_sdk-0.9.9/codecov.yml +25 -0
  83. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/cli-development-guide.md +2 -2
  84. affinity_sdk-0.9.9/docs/public/ai-integrations/index.md +77 -0
  85. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/cli/commands.md +212 -97
  86. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/cli/index.md +30 -0
  87. affinity_sdk-0.9.9/docs/public/cli/scripting.md +151 -0
  88. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/cli-reference.md +69 -8
  89. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/getting-started.md +1 -1
  90. affinity_sdk-0.9.9/docs/public/guides/claude-code-plugins.md +148 -0
  91. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/csv-export.md +51 -32
  92. affinity_sdk-0.9.9/docs/public/guides/datetime-handling.md +100 -0
  93. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/filtering.md +97 -34
  94. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/performance.md +12 -0
  95. affinity_sdk-0.9.9/docs/public/guides/query-command.md +498 -0
  96. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/index.md +1 -0
  97. affinity_sdk-0.9.9/docs/public/mcp/index.md +376 -0
  98. affinity_sdk-0.9.9/docs/public/reference/query-language.md +631 -0
  99. affinity_sdk-0.9.9/mcp/.claude-plugin/.gitignore +14 -0
  100. affinity_sdk-0.9.9/mcp/.claude-plugin/.mcp.json +6 -0
  101. affinity_sdk-0.9.9/mcp/.claude-plugin/plugin.json +26 -0
  102. affinity_sdk-0.9.9/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +225 -0
  103. affinity_sdk-0.9.9/mcp/.claude-plugin/skills/query-language/SKILL.md +629 -0
  104. affinity_sdk-0.9.9/mcp/.claude-plugin/xaffinity-mcp.sh +107 -0
  105. affinity_sdk-0.9.9/mcp/.gitignore +22 -0
  106. affinity_sdk-0.9.9/mcp/.registry/commands-metadata.json +109 -0
  107. affinity_sdk-0.9.9/mcp/.registry/commands.json +3018 -0
  108. affinity_sdk-0.9.9/mcp/.registry/prompts.json +253 -0
  109. affinity_sdk-0.9.9/mcp/.registry/resource-templates.json +30 -0
  110. affinity_sdk-0.9.9/mcp/.registry/resources.json +41 -0
  111. affinity_sdk-0.9.9/mcp/CHANGELOG.md +383 -0
  112. affinity_sdk-0.9.9/mcp/COMPATIBILITY +45 -0
  113. affinity_sdk-0.9.9/mcp/Makefile +120 -0
  114. affinity_sdk-0.9.9/mcp/README.md +352 -0
  115. affinity_sdk-0.9.9/mcp/VERSION +1 -0
  116. affinity_sdk-0.9.9/mcp/completions/entity-name.sh +51 -0
  117. affinity_sdk-0.9.9/mcp/completions/list-name.sh +42 -0
  118. affinity_sdk-0.9.9/mcp/completions/status-value.sh +46 -0
  119. affinity_sdk-0.9.9/mcp/docs/DEBUGGING.md +152 -0
  120. affinity_sdk-0.9.9/mcp/docs/internal/debugging-improvements-plan.md +375 -0
  121. affinity_sdk-0.9.9/mcp/docs/internal/mcp-bash-progress-timeout-feature-request.md +215 -0
  122. affinity_sdk-0.9.9/mcp/icon.svg +19 -0
  123. affinity_sdk-0.9.9/mcp/lib/cache.sh +124 -0
  124. affinity_sdk-0.9.9/mcp/lib/cli-gateway.sh +451 -0
  125. affinity_sdk-0.9.9/mcp/lib/common.sh +494 -0
  126. affinity_sdk-0.9.9/mcp/lib/entity-types.sh +84 -0
  127. affinity_sdk-0.9.9/mcp/lib/field-resolution.sh +124 -0
  128. affinity_sdk-0.9.9/mcp/mcp-bash.lock +5 -0
  129. affinity_sdk-0.9.9/mcp/mcpb.conf +24 -0
  130. affinity_sdk-0.9.9/mcp/prompts/change-status/change-status.meta.json +26 -0
  131. affinity_sdk-0.9.9/mcp/prompts/change-status/change-status.txt +13 -0
  132. affinity_sdk-0.9.9/mcp/prompts/interaction-brief/interaction-brief.meta.json +19 -0
  133. affinity_sdk-0.9.9/mcp/prompts/interaction-brief/interaction-brief.txt +13 -0
  134. affinity_sdk-0.9.9/mcp/prompts/log-call/log-call.meta.json +32 -0
  135. affinity_sdk-0.9.9/mcp/prompts/log-call/log-call.txt +16 -0
  136. affinity_sdk-0.9.9/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +27 -0
  137. affinity_sdk-0.9.9/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +16 -0
  138. affinity_sdk-0.9.9/mcp/prompts/log-message/log-message.meta.json +33 -0
  139. affinity_sdk-0.9.9/mcp/prompts/log-message/log-message.txt +16 -0
  140. affinity_sdk-0.9.9/mcp/prompts/pipeline-review/pipeline-review.meta.json +14 -0
  141. affinity_sdk-0.9.9/mcp/prompts/pipeline-review/pipeline-review.txt +17 -0
  142. affinity_sdk-0.9.9/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +19 -0
  143. affinity_sdk-0.9.9/mcp/prompts/prepare-briefing/prepare-briefing.txt +16 -0
  144. affinity_sdk-0.9.9/mcp/prompts/warm-intro/warm-intro.meta.json +18 -0
  145. affinity_sdk-0.9.9/mcp/prompts/warm-intro/warm-intro.txt +17 -0
  146. affinity_sdk-0.9.9/mcp/providers/xaffinity.sh +107 -0
  147. affinity_sdk-0.9.9/mcp/resources/data-model/data-model.md +211 -0
  148. affinity_sdk-0.9.9/mcp/resources/data-model/data-model.meta.json +7 -0
  149. affinity_sdk-0.9.9/mcp/resources/field-catalogs/field-catalogs.meta.json +7 -0
  150. affinity_sdk-0.9.9/mcp/resources/field-catalogs/field-catalogs.sh +91 -0
  151. affinity_sdk-0.9.9/mcp/resources/interaction-enums/interaction-enums.json +13 -0
  152. affinity_sdk-0.9.9/mcp/resources/interaction-enums/interaction-enums.meta.json +7 -0
  153. affinity_sdk-0.9.9/mcp/resources/me/me.meta.json +7 -0
  154. affinity_sdk-0.9.9/mcp/resources/me/me.sh +16 -0
  155. affinity_sdk-0.9.9/mcp/resources/me-person-id/me-person-id.meta.json +7 -0
  156. affinity_sdk-0.9.9/mcp/resources/me-person-id/me-person-id.sh +29 -0
  157. affinity_sdk-0.9.9/mcp/resources/saved-views/saved-views.meta.json +7 -0
  158. affinity_sdk-0.9.9/mcp/resources/saved-views/saved-views.sh +28 -0
  159. affinity_sdk-0.9.9/mcp/resources/workflow-config/workflow-config.meta.json +7 -0
  160. affinity_sdk-0.9.9/mcp/resources/workflow-config/workflow-config.sh +47 -0
  161. affinity_sdk-0.9.9/mcp/scripts/install-framework.sh +80 -0
  162. affinity_sdk-0.9.9/mcp/server.d/env.sh +74 -0
  163. affinity_sdk-0.9.9/mcp/server.d/health-checks.sh +32 -0
  164. affinity_sdk-0.9.9/mcp/server.d/policy.sh +32 -0
  165. affinity_sdk-0.9.9/mcp/server.d/requirements.json +29 -0
  166. affinity_sdk-0.9.9/mcp/server.d/server.meta.json +6 -0
  167. affinity_sdk-0.9.9/mcp/test/README.md +136 -0
  168. affinity_sdk-0.9.9/mcp/test/run.sh +450 -0
  169. affinity_sdk-0.9.9/mcp/test-progress.sh +254 -0
  170. affinity_sdk-0.9.9/mcp/tools/discover-commands/tool.meta.json +46 -0
  171. affinity_sdk-0.9.9/mcp/tools/discover-commands/tool.sh +152 -0
  172. affinity_sdk-0.9.9/mcp/tools/execute-read-command/tool.meta.json +42 -0
  173. affinity_sdk-0.9.9/mcp/tools/execute-read-command/tool.sh +176 -0
  174. affinity_sdk-0.9.9/mcp/tools/execute-write-command/tool.meta.json +36 -0
  175. affinity_sdk-0.9.9/mcp/tools/execute-write-command/tool.sh +227 -0
  176. affinity_sdk-0.9.9/mcp/tools/get-entity-dossier/tool.meta.json +46 -0
  177. affinity_sdk-0.9.9/mcp/tools/get-entity-dossier/tool.sh +131 -0
  178. affinity_sdk-0.9.9/mcp/tools/query/tool.meta.json +100 -0
  179. affinity_sdk-0.9.9/mcp/tools/query/tool.sh +106 -0
  180. affinity_sdk-0.9.9/mcp/tools/read-xaffinity-resource/tool.meta.json +19 -0
  181. affinity_sdk-0.9.9/mcp/tools/read-xaffinity-resource/tool.sh +23 -0
  182. affinity_sdk-0.9.9/mcp/xaffinity-mcp-env.sh +37 -0
  183. affinity_sdk-0.9.9/mcp/xaffinity-mcp.sh +178 -0
  184. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/mkdocs.yml +5 -2
  185. affinity_sdk-0.9.9/plugins/affinity-sdk/.claude-plugin/plugin.json +22 -0
  186. affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/SDK_REFERENCE.md → affinity_sdk-0.9.9/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +101 -72
  187. affinity_sdk-0.9.9/plugins/xaffinity-cli/.claude-plugin/commands/affinity-help.md +56 -0
  188. affinity_sdk-0.9.9/plugins/xaffinity-cli/.claude-plugin/plugin.json +28 -0
  189. affinity_sdk-0.9.9/plugins/xaffinity-cli/.claude-plugin/skills/xaffinity-cli-usage/SKILL.md +193 -0
  190. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/pyproject.toml +11 -4
  191. affinity_sdk-0.9.9/tests/cli/test_formatters.py +566 -0
  192. affinity_sdk-0.9.9/tests/cli/test_output_formats_integration.py +376 -0
  193. affinity_sdk-0.9.9/tests/test_cli_column_limiting.py +199 -0
  194. affinity_sdk-0.9.9/tests/test_cli_command_context.py +257 -0
  195. affinity_sdk-0.9.9/tests/test_cli_company_cmds_coverage.py +278 -0
  196. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_company_get.py +22 -9
  197. affinity_sdk-0.9.9/tests/test_cli_csv_export.py +1012 -0
  198. affinity_sdk-0.9.9/tests/test_cli_date_params.py +154 -0
  199. affinity_sdk-0.9.9/tests/test_cli_date_utils.py +82 -0
  200. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_datetime_formatting.py +1 -1
  201. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_datetime_header_offsets.py +1 -1
  202. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_domain_linkification.py +1 -1
  203. affinity_sdk-0.9.9/tests/test_cli_entry_field.py +1317 -0
  204. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_error_rendering.py +16 -4
  205. affinity_sdk-0.9.9/tests/test_cli_field_history.py +202 -0
  206. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_field_value_humanization.py +6 -6
  207. affinity_sdk-0.9.9/tests/test_cli_interaction_date_chunking.py +1044 -0
  208. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_json_safety.py +1 -1
  209. affinity_sdk-0.9.9/tests/test_cli_list_cmds_coverage.py +519 -0
  210. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_no_network_commands.py +2 -2
  211. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_opportunity_cmds.py +15 -14
  212. affinity_sdk-0.9.9/tests/test_cli_opportunity_cmds_coverage.py +155 -0
  213. affinity_sdk-0.9.9/tests/test_cli_person_cmds_coverage.py +348 -0
  214. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_person_get.py +1 -1
  215. affinity_sdk-0.9.9/tests/test_cli_progress_manager.py +164 -0
  216. affinity_sdk-0.9.9/tests/test_cli_query_aggregates.py +481 -0
  217. affinity_sdk-0.9.9/tests/test_cli_query_cmd.py +401 -0
  218. affinity_sdk-0.9.9/tests/test_cli_query_dates.py +205 -0
  219. affinity_sdk-0.9.9/tests/test_cli_query_executor.py +3850 -0
  220. affinity_sdk-0.9.9/tests/test_cli_query_filters.py +1354 -0
  221. affinity_sdk-0.9.9/tests/test_cli_query_integration.py +240 -0
  222. affinity_sdk-0.9.9/tests/test_cli_query_parser.py +869 -0
  223. affinity_sdk-0.9.9/tests/test_cli_query_planner.py +625 -0
  224. affinity_sdk-0.9.9/tests/test_cli_query_safety.py +258 -0
  225. affinity_sdk-0.9.9/tests/test_cli_query_schema.py +443 -0
  226. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_rate_limit_rendering.py +2 -2
  227. affinity_sdk-0.9.9/tests/test_cli_result_summary.py +237 -0
  228. affinity_sdk-0.9.9/tests/test_cli_session_cache.py +389 -0
  229. affinity_sdk-0.9.9/tests/test_cli_types.py +152 -0
  230. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_v1_only_cmds.py +21 -10
  231. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_write_ops.py +14 -13
  232. affinity_sdk-0.9.9/tests/test_compare.py +518 -0
  233. affinity_sdk-0.9.9/tests/test_exceptions_coverage.py +341 -0
  234. affinity_sdk-0.9.9/tests/test_filters.py +1071 -0
  235. affinity_sdk-0.9.9/tests/test_hooks.py +404 -0
  236. affinity_sdk-0.9.9/tests/test_isodatetime.py +433 -0
  237. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_models.py +4 -2
  238. affinity_sdk-0.9.9/tests/test_public_api.py +215 -0
  239. affinity_sdk-0.9.9/tests/test_services_companies_coverage_gaps.py +460 -0
  240. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_services_lists_additional_coverage.py +6 -8
  241. affinity_sdk-0.9.9/tests/test_services_lists_coverage_gaps.py +402 -0
  242. affinity_sdk-0.9.9/tests/test_services_opportunities_coverage_gaps.py +339 -0
  243. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_services_persons_companies_additional_coverage.py +519 -0
  244. affinity_sdk-0.9.9/tests/test_services_rate_limits_coverage_gaps.py +287 -0
  245. affinity_sdk-0.9.9/tests/test_services_v1_only_coverage_gaps.py +336 -0
  246. affinity_sdk-0.9.9/tools/generate_cli_commands_registry.py +200 -0
  247. affinity_sdk-0.9.9/tools/sync_mcp_registry.py +136 -0
  248. affinity_sdk-0.9.9/tools/sync_mcp_version.py +63 -0
  249. affinity_sdk-0.9.9/tools/sync_plugin_version.py +69 -0
  250. affinity_sdk-0.9.9/uv.lock +1485 -0
  251. affinity_sdk-0.4.7/.claude-plugin/commands/affinity-help.md +0 -58
  252. affinity_sdk-0.4.7/.claude-plugin/marketplace.json +0 -16
  253. affinity_sdk-0.4.7/.claude-plugin/plugin.json +0 -27
  254. affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/CLI_REFERENCE.md +0 -349
  255. affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/LIST_EXPORT_EXPAND.md +0 -177
  256. affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/SKILL.md +0 -213
  257. affinity_sdk-0.4.7/.github/workflows/ci.yml +0 -56
  258. affinity_sdk-0.4.7/.github/workflows/release.yml +0 -178
  259. affinity_sdk-0.4.7/CHANGELOG.md +0 -94
  260. affinity_sdk-0.4.7/affinity/cli/commands/field_cmds.py +0 -135
  261. affinity_sdk-0.4.7/affinity/cli/commands/interaction_cmds.py +0 -384
  262. affinity_sdk-0.4.7/affinity/cli/csv_utils.py +0 -120
  263. affinity_sdk-0.4.7/affinity/cli/progress.py +0 -99
  264. affinity_sdk-0.4.7/affinity/cli/resolve.py +0 -114
  265. affinity_sdk-0.4.7/affinity/cli/results.py +0 -44
  266. affinity_sdk-0.4.7/docs/public/cli/scripting.md +0 -41
  267. affinity_sdk-0.4.7/docs/public/guides/claude-code-plugin.md +0 -86
  268. affinity_sdk-0.4.7/docs/public/guides/v1-v2-routing.md +0 -3
  269. affinity_sdk-0.4.7/tests/test_cli_csv_export.py +0 -2770
  270. affinity_sdk-0.4.7/tests/test_cli_progress_manager.py +0 -9
  271. affinity_sdk-0.4.7/tests/test_filters.py +0 -390
  272. affinity_sdk-0.4.7/tools/sync_plugin_version.py +0 -48
  273. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.editorconfig +0 -0
  274. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.env.example +0 -0
  275. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.gitattributes +0 -0
  276. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/CODEOWNERS +0 -0
  277. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  278. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  279. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
  280. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/dependabot.yml +0 -0
  281. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/labels.yml +0 -0
  282. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/.github/pull_request_template.md +0 -0
  283. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/CODE_OF_CONDUCT.md +0 -0
  284. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/LICENSE +0 -0
  285. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/SECURITY.md +0 -0
  286. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/click_compat.py +0 -0
  287. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/__init__.py +0 -0
  288. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/commands/_list_entry_fields.py +0 -0
  289. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/config.py +0 -0
  290. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/errors.py +0 -0
  291. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/field_utils.py +0 -0
  292. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/logging.py +0 -0
  293. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/paths.py +0 -0
  294. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/resolvers.py +0 -0
  295. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/serialization.py +0 -0
  296. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/cli/types.py +0 -0
  297. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/clients/__init__.py +0 -0
  298. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/clients/pipeline.py +0 -0
  299. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/downloads.py +0 -0
  300. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/hooks.py +0 -0
  301. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/__init__.py +0 -0
  302. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/rate_limit_snapshot.py +0 -0
  303. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/models/secondary.py +0 -0
  304. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/policies.py +0 -0
  305. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/progress.py +0 -0
  306. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/py.typed +0 -0
  307. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/__init__.py +0 -0
  308. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/rate_limits.py +0 -0
  309. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/services/tasks.py +0 -0
  310. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/affinity/types.py +0 -0
  311. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/changelog.md +0 -0
  312. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/examples.md +0 -0
  313. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/glossary.md +0 -0
  314. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/api-versions-and-routing.md +0 -0
  315. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/authentication.md +0 -0
  316. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/configuration.md +0 -0
  317. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/debugging-hooks.md +0 -0
  318. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/errors-and-retries.md +0 -0
  319. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/field-types-and-values.md +0 -0
  320. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/field-values.md +0 -0
  321. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/ids-and-types.md +0 -0
  322. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/models.md +0 -0
  323. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/opportunity-associations.md +0 -0
  324. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/pagination.md +0 -0
  325. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/rate-limits.md +0 -0
  326. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/sync-vs-async.md +0 -0
  327. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/guides/webhooks.md +0 -0
  328. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/client.md +0 -0
  329. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/exceptions.md +0 -0
  330. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/filters.md +0 -0
  331. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/models.md +0 -0
  332. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/companies.md +0 -0
  333. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/lists.md +0 -0
  334. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/opportunities.md +0 -0
  335. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/persons.md +0 -0
  336. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/tasks.md +0 -0
  337. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/auth.md +0 -0
  338. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/field-values.md +0 -0
  339. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/fields.md +0 -0
  340. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/files.md +0 -0
  341. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/interactions.md +0 -0
  342. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/notes.md +0 -0
  343. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/relationships.md +0 -0
  344. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/reminders.md +0 -0
  345. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/services/v1/webhooks.md +0 -0
  346. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/reference/types.md +0 -0
  347. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/docs/public/troubleshooting.md +0 -0
  348. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/advanced_usage.py +0 -0
  349. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/async_lifecycle.py +0 -0
  350. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/basic_usage.py +0 -0
  351. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/filter_builder.py +0 -0
  352. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/hooks_debugging.py +0 -0
  353. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/list_management.py +0 -0
  354. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/resolve_helpers.py +0 -0
  355. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/examples/task_polling.py +0 -0
  356. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9/plugins/xaffinity-cli}/.claude-plugin/hooks/hooks.json +0 -0
  357. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9/plugins/xaffinity-cli}/.claude-plugin/hooks/pre-xaffinity.sh +0 -0
  358. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/conftest.py +0 -0
  359. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/field_value_updated.json +0 -0
  360. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/list_entry_created.json +0 -0
  361. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/organization_created.json +0 -0
  362. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/organization_merged.json +0 -0
  363. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/person_created.json +0 -0
  364. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/fixtures/webhooks/unknown_event.json +0 -0
  365. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
  366. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_async_file_download_streaming.py +0 -0
  367. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_config_cmds.py +0 -0
  368. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_entity_files_dump.py +0 -0
  369. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_missing_coverage.py +0 -0
  370. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_pager_logic.py +0 -0
  371. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_resolve_url_parsing.py +0 -0
  372. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_cli_serialization.py +0 -0
  373. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_client.py +0 -0
  374. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_env_helpers.py +0 -0
  375. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_field_value_type.py +0 -0
  376. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_file_download_streaming.py +0 -0
  377. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_file_upload_helpers_and_validation.py +0 -0
  378. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_http_client_additional_coverage.py +0 -0
  379. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_http_client_remaining_coverage.py +0 -0
  380. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_inbound_webhooks.py +0 -0
  381. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_integration_smoke.py +0 -0
  382. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_interactions_and_files_regressions.py +0 -0
  383. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_list_entry_membership_and_opportunities.py +0 -0
  384. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_new_features.py +0 -0
  385. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_pagination_iterators.py +0 -0
  386. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_raw_pipeline_hook_events.py +0 -0
  387. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_requirements_additional.py +0 -0
  388. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_services_opportunities_additional_coverage.py +0 -0
  389. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
  390. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_services_v1_only_async.py +0 -0
  391. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_small_modules_coverage.py +0 -0
  392. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_transport_and_readonly_mode.py +0 -0
  393. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_v1_only_services_additional_coverage.py +0 -0
  394. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tests/test_v1_only_services_more_coverage.py +0 -0
  395. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tools/check_cli_patterns.py +0 -0
  396. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tools/generate_requirements_mapping.py +0 -0
  397. {affinity_sdk-0.4.7 → affinity_sdk-0.9.9}/tools/validate_openapi_models.py +0 -0
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "xaffinity",
3
+ "owner": {
4
+ "name": "Yaniv Golan"
5
+ },
6
+ "metadata": {
7
+ "description": "Plugins for Affinity CRM - Python SDK, CLI, and MCP integrations"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "sdk",
12
+ "source": "./plugins/affinity-sdk/.claude-plugin",
13
+ "description": "Python SDK for Affinity CRM - typed IDs, async support, pagination patterns for developers"
14
+ },
15
+ {
16
+ "name": "cli",
17
+ "source": "./plugins/xaffinity-cli/.claude-plugin",
18
+ "description": "Command-line interface for Affinity CRM - search, export, filter CRM data via xaffinity commands"
19
+ },
20
+ {
21
+ "name": "mcp",
22
+ "source": "./mcp/.claude-plugin",
23
+ "description": "MCP server for Affinity CRM - workflow tools, relationship intelligence, pipeline management"
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Release
3
+ about: Checklist for SDK or MCP releases
4
+ ---
5
+
6
+ ## Release Type
7
+
8
+ - [ ] SDK Release (vX.Y.Z)
9
+ - [ ] MCP Release (plugin-vX.Y.Z)
10
+
11
+ ## SDK Release Checklist (vX.Y.Z)
12
+
13
+ - [ ] Version bumped in `pyproject.toml`
14
+ - [ ] Plugin versions synced (pre-commit should handle)
15
+ - [ ] `CHANGELOG.md` updated with breaking changes noted
16
+ - [ ] If CLI output format changed: MCP `COMPATIBILITY` updated
17
+ - [ ] Tests pass locally and in CI
18
+
19
+ ## MCP Release Checklist (plugin-vX.Y.Z)
20
+
21
+ - [ ] Version bumped in `mcp/VERSION`
22
+ - [ ] `mcp/.claude-plugin/plugin.json` version updated
23
+ - [ ] `mcp/mcpb.conf` MCPB_VERSION updated
24
+ - [ ] `mcp/COMPATIBILITY` CLI requirements updated if needed
25
+ - [ ] `mcp/CHANGELOG.md` documents CLI compatibility
26
+ - [ ] Builds successfully: `cd mcp && make all verify`
27
+
28
+ ## Post-Merge
29
+
30
+ - [ ] Tag pushed: `git tag vX.Y.Z && git push --tags` (SDK)
31
+ - [ ] Tag pushed: `git tag plugin-vX.Y.Z && git push --tags` (MCP)
@@ -0,0 +1,134 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ mcp-plugin:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v6
12
+
13
+ - name: Build MCP plugin
14
+ run: make -C mcp plugin
15
+
16
+ - name: Verify plugin structure
17
+ run: |
18
+ # Ensure critical files exist after build (ZIP-based distribution)
19
+ make -C mcp verify
20
+ test -f mcp/.claude-plugin/xaffinity-mcp.sh
21
+ test -f mcp/.claude-plugin/plugin.json
22
+ test -f mcp/.claude-plugin/xaffinity-mcp-plugin.zip
23
+ test -f mcp/.claude-plugin/VERSION
24
+ echo "Plugin structure validated successfully"
25
+
26
+ - name: Test ZIP extraction
27
+ run: |
28
+ cd mcp/.claude-plugin
29
+ mkdir -p .mcp-extracted
30
+ unzip -q xaffinity-mcp-plugin.zip -d .mcp-extracted
31
+ test -x .mcp-extracted/xaffinity-mcp.sh
32
+ test -d .mcp-extracted/tools
33
+ test -d .mcp-extracted/prompts
34
+ echo "ZIP extraction test passed"
35
+
36
+ test:
37
+ runs-on: ubuntu-latest
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
42
+
43
+ steps:
44
+ - uses: actions/checkout@v6
45
+
46
+ - name: Set up Python
47
+ uses: actions/setup-python@v6
48
+ with:
49
+ python-version: ${{ matrix.python-version }}
50
+ cache: pip
51
+ cache-dependency-path: pyproject.toml
52
+
53
+ - name: Install
54
+ run: |
55
+ python -m pip install --upgrade pip
56
+ python -m pip install -e ".[dev]"
57
+
58
+ - name: Lint
59
+ run: |
60
+ ruff format --check .
61
+ ruff check .
62
+
63
+ - name: Type check
64
+ run: |
65
+ mypy affinity
66
+
67
+ - name: Test
68
+ run: |
69
+ pytest --cov=affinity --cov-report=term-missing --cov-report=xml
70
+
71
+ - name: Upload coverage to Codecov
72
+ uses: codecov/codecov-action@v5
73
+ with:
74
+ token: ${{ secrets.CODECOV_TOKEN }}
75
+ files: ./coverage.xml
76
+ fail_ci_if_error: false
77
+
78
+ - name: Traceability mapping is up to date
79
+ run: |
80
+ if [ -d docs/internal ]; then
81
+ python tools/generate_requirements_mapping.py
82
+ git diff --exit-code docs/internal/requirements_to_tests_mapping.md
83
+ else
84
+ echo "Skipping traceability mapping (docs/internal not present in repo checkout)."
85
+ fi
86
+
87
+ - name: CLI commands registry is valid
88
+ run: |
89
+ # Verify registry file exists and is valid JSON with expected structure
90
+ python -c "
91
+ import json
92
+ import sys
93
+ with open('mcp/.registry/commands.json') as f:
94
+ data = json.load(f)
95
+ assert 'commands' in data, 'Missing commands key'
96
+ assert isinstance(data['commands'], list), 'commands must be a list'
97
+ assert len(data['commands']) > 0, 'commands list is empty'
98
+ for cmd in data['commands']:
99
+ assert 'name' in cmd, f'Command missing name: {cmd}'
100
+ assert 'category' in cmd, f'Command {cmd[\"name\"]} missing category'
101
+ assert cmd['category'] in ('read', 'write', 'local'), f'Invalid category for {cmd[\"name\"]}'
102
+ print(f'Registry valid: {len(data[\"commands\"])} commands')
103
+ "
104
+ # Regenerate registry and verify it matches committed version
105
+ python tools/generate_cli_commands_registry.py
106
+ git diff --exit-code mcp/.registry/commands.json
107
+
108
+ test-timezone:
109
+ runs-on: ubuntu-latest
110
+ strategy:
111
+ fail-fast: false
112
+ matrix:
113
+ tz: ["UTC", "America/New_York", "Europe/London", "Asia/Tokyo"]
114
+
115
+ steps:
116
+ - uses: actions/checkout@v6
117
+
118
+ - name: Set up Python
119
+ uses: actions/setup-python@v6
120
+ with:
121
+ python-version: "3.12"
122
+ cache: pip
123
+ cache-dependency-path: pyproject.toml
124
+
125
+ - name: Install
126
+ run: |
127
+ python -m pip install --upgrade pip
128
+ python -m pip install -e ".[dev]"
129
+
130
+ - name: Test with TZ=${{ matrix.tz }}
131
+ env:
132
+ TZ: ${{ matrix.tz }}
133
+ run: |
134
+ pytest tests/test_isodatetime.py -v
@@ -13,12 +13,12 @@ jobs:
13
13
  build:
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@v6
17
17
  with:
18
18
  fetch-depth: 0
19
19
 
20
20
  - name: Set up Python
21
- uses: actions/setup-python@v5
21
+ uses: actions/setup-python@v6
22
22
  with:
23
23
  python-version: "3.12"
24
24
  cache: pip
@@ -54,14 +54,14 @@ jobs:
54
54
  contents: write
55
55
  concurrency:
56
56
  group: docs-deploy
57
- cancel-in-progress: true
57
+ cancel-in-progress: false
58
58
  steps:
59
- - uses: actions/checkout@v4
59
+ - uses: actions/checkout@v6
60
60
  with:
61
61
  fetch-depth: 0
62
62
 
63
63
  - name: Set up Python
64
- uses: actions/setup-python@v5
64
+ uses: actions/setup-python@v6
65
65
  with:
66
66
  python-version: "3.12"
67
67
  cache: pip
@@ -81,6 +81,10 @@ jobs:
81
81
  git config user.name "github-actions[bot]"
82
82
  git config user.email "github-actions[bot]@users.noreply.github.com"
83
83
 
84
+ - name: Fetch gh-pages branch
85
+ run: |
86
+ git fetch origin gh-pages:gh-pages || true
87
+
84
88
  - name: Deploy (dev)
85
89
  if: github.ref == 'refs/heads/main'
86
90
  run: |
@@ -15,7 +15,7 @@ jobs:
15
15
  sync:
16
16
  runs-on: ubuntu-latest
17
17
  steps:
18
- - uses: actions/checkout@v4
18
+ - uses: actions/checkout@v6
19
19
  - name: Sync labels
20
20
  uses: EndBug/label-sync@v2
21
21
  with:
@@ -13,10 +13,10 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  timeout-minutes: 10
15
15
  steps:
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@v6
17
17
 
18
18
  - name: Set up Python
19
- uses: actions/setup-python@v5
19
+ uses: actions/setup-python@v6
20
20
  with:
21
21
  python-version: "3.12"
22
22
  cache: pip
@@ -11,10 +11,10 @@ jobs:
11
11
  timeout-minutes: 10
12
12
 
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@v6
15
15
 
16
16
  - name: Set up Python
17
- uses: actions/setup-python@v5
17
+ uses: actions/setup-python@v6
18
18
  with:
19
19
  python-version: "3.12"
20
20
  cache: pip
@@ -0,0 +1,106 @@
1
+ name: Build MCP Plugin
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - 'mcp/**'
8
+ - '!mcp/dist/**'
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+ with:
20
+ token: ${{ secrets.GITHUB_TOKEN }}
21
+
22
+ - name: Install jq
23
+ run: sudo apt-get install -y jq
24
+
25
+ - name: Install mcp-bash framework
26
+ run: |
27
+ # Source version and commit from lockfile (single source of truth)
28
+ source mcp/mcp-bash.lock
29
+ echo "Installing mcp-bash v${MCPBASH_VERSION} (${MCPBASH_COMMIT})"
30
+ curl -fsSL https://raw.githubusercontent.com/yaniv-golan/mcp-bash-framework/main/install.sh | \
31
+ bash -s -- --version "v${MCPBASH_VERSION}" --yes
32
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
33
+ # Verify installed commit matches lockfile
34
+ INSTALLED_COMMIT=$(git -C "${XDG_DATA_HOME:-$HOME/.local/share}/mcp-bash" rev-parse HEAD)
35
+ if [[ "$INSTALLED_COMMIT" != "$MCPBASH_COMMIT" ]]; then
36
+ echo "::error::mcp-bash commit mismatch: expected $MCPBASH_COMMIT, got $INSTALLED_COMMIT"
37
+ exit 1
38
+ fi
39
+
40
+ - name: Verify mcp-bash installation
41
+ run: |
42
+ mcp-bash --version
43
+ echo "mcp-bash installed successfully"
44
+
45
+ - name: Build MCP plugin ZIP
46
+ run: make -C mcp plugin
47
+
48
+ - name: Verify plugin structure
49
+ run: |
50
+ make -C mcp verify
51
+ test -f mcp/.claude-plugin/xaffinity-mcp.sh
52
+ test -f mcp/.claude-plugin/plugin.json
53
+ test -f mcp/.claude-plugin/xaffinity-mcp-plugin.zip
54
+ test -f mcp/.claude-plugin/VERSION
55
+ echo "Plugin structure validated"
56
+
57
+ - name: Test extraction
58
+ run: |
59
+ cd mcp/.claude-plugin
60
+ mkdir -p .mcp-extracted
61
+ unzip -q xaffinity-mcp-plugin.zip -d .mcp-extracted
62
+ test -x .mcp-extracted/xaffinity-mcp.sh
63
+ test -f .mcp-extracted/VERSION
64
+ rm -rf .mcp-extracted
65
+ echo "Extraction test passed"
66
+
67
+ - name: Validate MCPB configuration
68
+ run: |
69
+ cd mcp
70
+ mcp-bash bundle --validate
71
+ echo "MCPB configuration validated"
72
+
73
+ - name: Build MCPB bundle
74
+ run: |
75
+ cd mcp
76
+ mcp-bash bundle --output dist --verbose
77
+ ls -la dist/*.mcpb
78
+ echo "MCPB bundle created"
79
+
80
+ - name: Validate MCPB bundle structure
81
+ run: |
82
+ cd mcp
83
+ MCPB_FILE=$(ls dist/*.mcpb | head -1)
84
+ unzip -t "$MCPB_FILE"
85
+ unzip -p "$MCPB_FILE" manifest.json | jq .
86
+ echo "MCPB bundle structure validated"
87
+
88
+ - name: Test MCPB bundle health check
89
+ run: |
90
+ cd mcp
91
+ MCPB_FILE=$(ls dist/*.mcpb | head -1)
92
+ EXTRACT_DIR=$(mktemp -d)
93
+ unzip -q "$MCPB_FILE" -d "$EXTRACT_DIR"
94
+ # Test the wrapper script health check
95
+ "$EXTRACT_DIR/server/run-server.sh" --health || echo "Health check not available (expected if CLI not configured)"
96
+ rm -rf "$EXTRACT_DIR"
97
+ echo "MCPB bundle test completed"
98
+
99
+ - name: Upload plugin artifacts
100
+ uses: actions/upload-artifact@v6
101
+ with:
102
+ name: mcp-plugin
103
+ path: |
104
+ mcp/.claude-plugin/xaffinity-mcp-plugin.zip
105
+ mcp/dist/*.mcpb
106
+ retention-days: 30
@@ -0,0 +1,163 @@
1
+ name: Release MCP Plugin
2
+
3
+ on:
4
+ push:
5
+ tags: ["mcp-v*.*.*"] # Renamed from plugin-v*
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Version to release (without prefix, for API trigger)"
10
+ required: false
11
+ type: string
12
+ triggered_by:
13
+ description: "What triggered this release"
14
+ required: false
15
+ type: string
16
+ default: "manual"
17
+ tag:
18
+ description: 'Tag to release manually (e.g., mcp-v1.0.0, ignored if version set)'
19
+ required: false
20
+
21
+ permissions:
22
+ contents: write
23
+
24
+ jobs:
25
+ release:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - name: Determine version and tag
29
+ id: version
30
+ run: |
31
+ set -euo pipefail
32
+ if [[ -n "${{ inputs.version }}" ]]; then
33
+ # API-triggered release (from release-detect)
34
+ # Note: Version validation happens post-checkout in "Validate version matches VERSION file" step
35
+ echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
36
+ echo "tag_name=mcp-v${{ inputs.version }}" >> $GITHUB_OUTPUT
37
+ echo "is_api_trigger=true" >> $GITHUB_OUTPUT
38
+ echo "Mode: workflow_dispatch (API), version=${{ inputs.version }}, triggered_by=${{ inputs.triggered_by }}"
39
+ elif [[ "${GITHUB_EVENT_NAME}" == "push" && "${GITHUB_REF_TYPE}" == "tag" ]]; then
40
+ # Tag push
41
+ TAG_NAME="${GITHUB_REF_NAME}"
42
+ VERSION="${TAG_NAME#mcp-v}"
43
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
44
+ echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
45
+ echo "is_api_trigger=false" >> $GITHUB_OUTPUT
46
+ echo "Mode: tag push, tag=$TAG_NAME, version=$VERSION"
47
+ else
48
+ # Manual workflow_dispatch with tag input
49
+ TAG_NAME="${{ inputs.tag }}"
50
+ if [[ -z "$TAG_NAME" ]]; then
51
+ echo "::error::Manual dispatch requires either 'version' or 'tag' input"
52
+ exit 1
53
+ fi
54
+ VERSION="${TAG_NAME#mcp-v}"
55
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
56
+ echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
57
+ echo "is_api_trigger=false" >> $GITHUB_OUTPUT
58
+ echo "Mode: workflow_dispatch (manual), tag=$TAG_NAME, version=$VERSION"
59
+ fi
60
+
61
+ - uses: actions/checkout@v6
62
+ with:
63
+ ref: ${{ steps.version.outputs.is_api_trigger == 'true' && 'main' || (github.event.inputs.tag || github.ref) }}
64
+
65
+ - name: Validate version matches VERSION file
66
+ run: |
67
+ set -euo pipefail
68
+ FILE_VERSION=$(cat mcp/VERSION | tr -d '[:space:]')
69
+ INPUT_VERSION="${{ steps.version.outputs.version }}"
70
+ if [[ "$FILE_VERSION" != "$INPUT_VERSION" ]]; then
71
+ echo "::error::Version mismatch: mcp/VERSION=$FILE_VERSION, expected=$INPUT_VERSION"
72
+ exit 1
73
+ fi
74
+ echo "Version validated: $FILE_VERSION"
75
+
76
+ - name: Install jq
77
+ run: sudo apt-get install -y jq
78
+
79
+ - name: Install mcp-bash framework
80
+ run: |
81
+ # Source version and commit from lockfile (single source of truth)
82
+ source mcp/mcp-bash.lock
83
+ echo "Installing mcp-bash v${MCPBASH_VERSION} (${MCPBASH_COMMIT})"
84
+ curl -fsSL https://raw.githubusercontent.com/yaniv-golan/mcp-bash-framework/main/install.sh | \
85
+ bash -s -- --version "v${MCPBASH_VERSION}" --yes
86
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
87
+ # Verify installed commit matches lockfile
88
+ INSTALLED_COMMIT=$(git -C "${XDG_DATA_HOME:-$HOME/.local/share}/mcp-bash" rev-parse HEAD)
89
+ if [[ "$INSTALLED_COMMIT" != "$MCPBASH_COMMIT" ]]; then
90
+ echo "::error::mcp-bash commit mismatch: expected $MCPBASH_COMMIT, got $INSTALLED_COMMIT"
91
+ exit 1
92
+ fi
93
+
94
+ - name: Verify mcp-bash installation
95
+ run: mcp-bash --version
96
+
97
+ - name: Build Claude Code plugin ZIP
98
+ run: |
99
+ cd mcp
100
+ make plugin
101
+ echo "Plugin version: $(cat .claude-plugin/VERSION)"
102
+ ls -la .claude-plugin/xaffinity-mcp-plugin.zip
103
+
104
+ - name: Validate MCPB configuration
105
+ run: |
106
+ cd mcp
107
+ mcp-bash bundle --validate
108
+
109
+ - name: Build MCPB bundle
110
+ run: |
111
+ cd mcp
112
+ mcp-bash bundle --output dist --verbose
113
+ ls -la dist/*.mcpb
114
+
115
+ - name: Validate MCPB bundle structure
116
+ run: |
117
+ cd mcp
118
+ MCPB_FILE=$(ls dist/*.mcpb | head -1)
119
+ unzip -t "$MCPB_FILE"
120
+ unzip -p "$MCPB_FILE" manifest.json | jq .
121
+ echo "MCPB bundle validated"
122
+
123
+ - name: Test MCPB bundle health check
124
+ run: |
125
+ cd mcp
126
+ MCPB_FILE=$(ls dist/*.mcpb | head -1)
127
+ EXTRACT_DIR=$(mktemp -d)
128
+ unzip -q "$MCPB_FILE" -d "$EXTRACT_DIR"
129
+ "$EXTRACT_DIR/server/run-server.sh" --health || echo "Health check not available (expected if CLI not configured)"
130
+ rm -rf "$EXTRACT_DIR"
131
+
132
+ - name: Create and push tag (API trigger only)
133
+ if: steps.version.outputs.is_api_trigger == 'true'
134
+ run: |
135
+ git config user.name "github-actions[bot]"
136
+ git config user.email "github-actions[bot]@users.noreply.github.com"
137
+ git tag -a "${{ steps.version.outputs.tag_name }}" -m "Release ${{ steps.version.outputs.tag_name }}"
138
+ git push origin "${{ steps.version.outputs.tag_name }}"
139
+
140
+ - name: Create GitHub Release
141
+ uses: softprops/action-gh-release@v2
142
+ with:
143
+ tag_name: ${{ steps.version.outputs.tag_name }}
144
+ files: |
145
+ mcp/.claude-plugin/xaffinity-mcp-plugin.zip
146
+ mcp/dist/*.mcpb
147
+ generate_release_notes: true
148
+ name: MCP Server ${{ steps.version.outputs.tag_name }}
149
+ body: |
150
+ ## Installation
151
+
152
+ ### One-click install (Claude Desktop)
153
+ Download `xaffinity-mcp-*.mcpb` and double-click or drag to Claude Desktop.
154
+
155
+ ### Claude Code
156
+ ```bash
157
+ /plugin marketplace add yaniv-golan/affinity-sdk
158
+ /plugin install mcp@xaffinity
159
+ ```
160
+
161
+ ### Manual configuration
162
+ Download `xaffinity-mcp-plugin.zip` and configure your MCP client manually.
163
+ See [documentation](https://yaniv-golan.github.io/affinity-sdk/latest/mcp/) for details.
@@ -0,0 +1,135 @@
1
+ name: Release Detection
2
+
3
+ # Triggers releases automatically when version files change on main
4
+ # Only runs AFTER CI passes successfully
5
+ #
6
+ # Detection strategy: Compare current version against existing release tags.
7
+ # This is more robust than checking HEAD~1 because it works regardless of
8
+ # how many commits are pushed together, squash merges, rebases, etc.
9
+
10
+ on:
11
+ workflow_run:
12
+ workflows: ["CI"]
13
+ types: [completed]
14
+ branches: [main]
15
+
16
+ permissions:
17
+ contents: read
18
+ actions: write # Required for workflow_dispatch API
19
+
20
+ jobs:
21
+ detect-changes:
22
+ # Only run if CI passed and it was a push (not PR)
23
+ if: >
24
+ github.event.workflow_run.conclusion == 'success' &&
25
+ github.event.workflow_run.event == 'push'
26
+ runs-on: ubuntu-latest
27
+ outputs:
28
+ sdk_changed: ${{ steps.changes.outputs.sdk }}
29
+ mcp_changed: ${{ steps.changes.outputs.mcp }}
30
+ sdk_version: ${{ steps.versions.outputs.sdk }}
31
+ mcp_version: ${{ steps.versions.outputs.mcp }}
32
+ steps:
33
+ - uses: actions/checkout@v6
34
+ with:
35
+ ref: ${{ github.event.workflow_run.head_sha }}
36
+ fetch-depth: 0 # Full history needed to check tags
37
+
38
+ - name: Extract versions
39
+ id: versions
40
+ run: |
41
+ set -euo pipefail
42
+ SDK_VERSION=$(grep '^version = ' pyproject.toml | head -1 | cut -d'"' -f2)
43
+ MCP_VERSION=$(cat mcp/VERSION | tr -d '[:space:]')
44
+ echo "sdk=$SDK_VERSION" >> $GITHUB_OUTPUT
45
+ echo "mcp=$MCP_VERSION" >> $GITHUB_OUTPUT
46
+ echo "SDK version in pyproject.toml: $SDK_VERSION"
47
+ echo "MCP version in mcp/VERSION: $MCP_VERSION"
48
+
49
+ - name: Detect unreleased versions
50
+ id: changes
51
+ run: |
52
+ set -euo pipefail
53
+
54
+ SDK_VERSION="${{ steps.versions.outputs.sdk }}"
55
+ MCP_VERSION="${{ steps.versions.outputs.mcp }}"
56
+
57
+ echo "Checking if releases exist for current versions..."
58
+
59
+ # Check if SDK version has a release tag
60
+ SDK_TAG="v${SDK_VERSION}"
61
+ if git tag -l "$SDK_TAG" | grep -q "^${SDK_TAG}$"; then
62
+ echo "SDK tag $SDK_TAG already exists - no release needed"
63
+ else
64
+ echo "SDK tag $SDK_TAG does not exist - release needed"
65
+ echo "sdk=true" >> $GITHUB_OUTPUT
66
+ fi
67
+
68
+ # Check if MCP version has a release tag
69
+ MCP_TAG="mcp-v${MCP_VERSION}"
70
+ if git tag -l "$MCP_TAG" | grep -q "^${MCP_TAG}$"; then
71
+ echo "MCP tag $MCP_TAG already exists - no release needed"
72
+ else
73
+ echo "MCP tag $MCP_TAG does not exist - release needed"
74
+ echo "mcp=true" >> $GITHUB_OUTPUT
75
+ fi
76
+
77
+ trigger-sdk-release:
78
+ needs: detect-changes
79
+ if: needs.detect-changes.outputs.sdk_changed == 'true'
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - name: Trigger SDK release workflow
83
+ uses: actions/github-script@v7
84
+ with:
85
+ script: |
86
+ // Use toJSON for safe string interpolation
87
+ const version = ${{ toJSON(needs.detect-changes.outputs.sdk_version) }};
88
+ console.log(`Triggering SDK release workflow for version ${version}`);
89
+
90
+ try {
91
+ await github.rest.actions.createWorkflowDispatch({
92
+ owner: context.repo.owner,
93
+ repo: context.repo.repo,
94
+ workflow_id: 'release.yml',
95
+ ref: 'main',
96
+ inputs: {
97
+ version: version,
98
+ triggered_by: 'release-detect'
99
+ }
100
+ });
101
+ console.log(`✅ SDK release workflow triggered successfully for v${version}`);
102
+ } catch (error) {
103
+ console.error(`❌ Failed to trigger SDK release: ${error.message}`);
104
+ core.setFailed(`Failed to trigger SDK release workflow: ${error.message}`);
105
+ }
106
+
107
+ trigger-mcp-release:
108
+ needs: detect-changes
109
+ if: needs.detect-changes.outputs.mcp_changed == 'true'
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - name: Trigger MCP plugin release workflow
113
+ uses: actions/github-script@v7
114
+ with:
115
+ script: |
116
+ // Use toJSON for safe string interpolation
117
+ const version = ${{ toJSON(needs.detect-changes.outputs.mcp_version) }};
118
+ console.log(`Triggering MCP plugin release workflow for version ${version}`);
119
+
120
+ try {
121
+ await github.rest.actions.createWorkflowDispatch({
122
+ owner: context.repo.owner,
123
+ repo: context.repo.repo,
124
+ workflow_id: 'plugin-release.yml',
125
+ ref: 'main',
126
+ inputs: {
127
+ version: version,
128
+ triggered_by: 'release-detect'
129
+ }
130
+ });
131
+ console.log(`✅ MCP release workflow triggered successfully for v${version}`);
132
+ } catch (error) {
133
+ console.error(`❌ Failed to trigger MCP release: ${error.message}`);
134
+ core.setFailed(`Failed to trigger MCP release workflow: ${error.message}`);
135
+ }