affinity-sdk 2.0.6__tar.gz → 2.0.8__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 (714) hide show
  1. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CHANGELOG.md +63 -0
  2. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/PKG-INFO +1 -1
  3. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/pushdown.py +104 -8
  4. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/company_cmds.py +10 -3
  5. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/list_cmds.py +100 -54
  6. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/person_cmds.py +10 -3
  7. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/entity_search.py +4 -3
  8. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/options.py +24 -0
  9. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/executor.py +18 -6
  10. affinity_sdk-2.0.8/affinity/cli/query/pushdown.py +25 -0
  11. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/compare.py +72 -3
  12. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/commands.md +6 -6
  13. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/filtering.md +30 -12
  14. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/query-command.md +4 -4
  15. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/query-language.md +2 -2
  16. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/plugin.json +1 -1
  17. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/SKILL.md +4 -4
  18. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/filter-operators.md +1 -1
  19. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/commands.generated.json +10 -6
  20. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/CHANGELOG.md +41 -0
  21. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/COMPATIBILITY +16 -2
  22. affinity_sdk-2.0.8/mcp/VERSION +1 -0
  23. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cli-gateway.sh +10 -0
  24. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.md +5 -5
  25. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/requirements.json +1 -1
  26. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/server.meta.json +1 -1
  27. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.meta.json +1 -1
  28. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/query/tool.meta.json +1 -1
  29. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/.claude-plugin/plugin.json +1 -1
  30. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/pre-xaffinity.sh +2 -2
  31. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/session-setup.sh +1 -1
  32. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/SKILL.md +3 -2
  33. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/filtering.md +17 -6
  34. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/query-guide.md +15 -7
  35. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/setup.md +1 -1
  36. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/pyproject.toml +1 -1
  37. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/company-lists-status.cassette.json +89 -89
  38. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/hook-blocks-without-key.cassette.json +66 -66
  39. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/no-key-skill-path.cassette.json +105 -104
  40. affinity_sdk-2.0.8/tests/cowork/cassettes/status-history.cassette.json +469 -0
  41. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_ls_server_filter.py +187 -0
  42. affinity_sdk-2.0.8/tests/test_cli_list_export_server_filter.py +661 -0
  43. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_executor.py +87 -1
  44. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_server_filter.py +191 -5
  45. affinity_sdk-2.0.8/tests/test_cli_repeated_filter.py +90 -0
  46. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_compare.py +2 -1
  47. affinity_sdk-2.0.8/tests/test_compare_entity_ids.py +159 -0
  48. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_entries_server_filter.py +81 -1
  49. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_must_fix.py +25 -0
  50. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_query_pushdown.py +231 -1
  51. affinity_sdk-2.0.8/tools/search_golden.py +478 -0
  52. affinity_sdk-2.0.6/affinity/cli/query/pushdown.py +0 -12
  53. affinity_sdk-2.0.6/mcp/VERSION +0 -1
  54. affinity_sdk-2.0.6/tests/cowork/cassettes/status-history.cassette.json +0 -462
  55. affinity_sdk-2.0.6/tests/test_cli_list_export_server_filter.py +0 -216
  56. affinity_sdk-2.0.6/tools/search_golden.py +0 -238
  57. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.claude-plugin/marketplace.json +0 -0
  58. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.cursor/rules/test-data-privacy.mdc +0 -0
  59. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.editorconfig +0 -0
  60. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.env.example +0 -0
  61. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.gitattributes +0 -0
  62. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/CODEOWNERS +0 -0
  63. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  64. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  65. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
  66. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/release.md +0 -0
  67. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/dependabot.yml +0 -0
  68. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/labels.yml +0 -0
  69. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/mcp-release-install-footer.md +0 -0
  70. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/pull_request_template.md +0 -0
  71. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/release-install-footer.md +0 -0
  72. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/ci.yml +0 -0
  73. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/cowork-replay.yml +0 -0
  74. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/docs.yml +0 -0
  75. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/labels.yml +0 -0
  76. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/linkcheck.yml +0 -0
  77. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/openapi-validation.yml +0 -0
  78. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/plugin-build.yml +0 -0
  79. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/plugin-release.yml +0 -0
  80. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/release-detect.yml +0 -0
  81. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/release.yml +0 -0
  82. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/version-check.yml +0 -0
  83. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.gitignore +0 -0
  84. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.pre-commit-config.yaml +0 -0
  85. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/AGENTS.md +0 -0
  86. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CODE_OF_CONDUCT.md +0 -0
  87. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CONTRIBUTING.md +0 -0
  88. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/LICENSE +0 -0
  89. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/README.md +0 -0
  90. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/SECURITY.md +0 -0
  91. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/VERSIONING.md +0 -0
  92. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/__init__.py +0 -0
  93. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/__init__.py +0 -0
  94. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/dates.py +0 -0
  95. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/filter_text.py +0 -0
  96. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/search.py +0 -0
  97. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/where.py +0 -0
  98. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_internal/__init__.py +0 -0
  99. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_internal/keyfile.py +0 -0
  100. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/api_versions.py +0 -0
  101. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/__init__.py +0 -0
  102. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/__main__.py +0 -0
  103. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/_update_worker.py +0 -0
  104. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/async_utils.py +0 -0
  105. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/click_compat.py +0 -0
  106. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/__init__.py +0 -0
  107. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_field.py +0 -0
  108. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_dump.py +0 -0
  109. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_read.py +0 -0
  110. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_upload.py +0 -0
  111. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_list_entry_fields.py +0 -0
  112. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_org_reads.py +0 -0
  113. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_search_common.py +0 -0
  114. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_v1_parsing.py +0 -0
  115. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/completion_cmd.py +0 -0
  116. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/config_cmds.py +0 -0
  117. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/discovery_cmds.py +0 -0
  118. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/entry_cmds.py +0 -0
  119. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/field_cmds.py +0 -0
  120. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/file_cmds.py +0 -0
  121. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/file_url_cmd.py +0 -0
  122. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/interaction_cmds.py +0 -0
  123. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/note_cmds.py +0 -0
  124. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/opportunity_cmds.py +0 -0
  125. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/org_cmds.py +0 -0
  126. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/org_read_cmds.py +0 -0
  127. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/query_cmd.py +0 -0
  128. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/relationship_strength_cmds.py +0 -0
  129. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/reminder_cmds.py +0 -0
  130. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/resolve_url_cmd.py +0 -0
  131. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/session_cmds.py +0 -0
  132. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/task_cmds.py +0 -0
  133. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/transcript_cmds.py +0 -0
  134. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/version_cmd.py +0 -0
  135. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/webhook_cmds.py +0 -0
  136. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/whoami_cmd.py +0 -0
  137. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/config.py +0 -0
  138. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/confirm.py +0 -0
  139. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/constants.py +0 -0
  140. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/context.py +0 -0
  141. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/csv_utils.py +0 -0
  142. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/date_utils.py +0 -0
  143. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/decorators.py +0 -0
  144. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/errors.py +0 -0
  145. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/field_utils.py +0 -0
  146. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/formatters.py +0 -0
  147. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/help_json.py +0 -0
  148. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/interaction_utils.py +0 -0
  149. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/list_search.py +0 -0
  150. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/logging.py +0 -0
  151. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/main.py +0 -0
  152. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/mcp_limits.py +0 -0
  153. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/paths.py +0 -0
  154. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/progress.py +0 -0
  155. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/__init__.py +0 -0
  156. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/aggregates.py +0 -0
  157. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/cursor.py +0 -0
  158. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/dates.py +0 -0
  159. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/exceptions.py +0 -0
  160. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/filter_text.py +0 -0
  161. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/filters.py +0 -0
  162. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/models.py +0 -0
  163. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/output.py +0 -0
  164. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/parser.py +0 -0
  165. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/planner.py +0 -0
  166. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/progress.py +0 -0
  167. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/schema.py +0 -0
  168. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/render.py +0 -0
  169. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/resolve.py +0 -0
  170. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/resolvers.py +0 -0
  171. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/results.py +0 -0
  172. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/runner.py +0 -0
  173. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/serialization.py +0 -0
  174. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/session_cache.py +0 -0
  175. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/types.py +0 -0
  176. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/update_check.py +0 -0
  177. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/client.py +0 -0
  178. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/__init__.py +0 -0
  179. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/http.py +0 -0
  180. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/pipeline.py +0 -0
  181. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/criteria.py +0 -0
  182. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/downloads.py +0 -0
  183. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/exceptions.py +0 -0
  184. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/field_resolve_utils.py +0 -0
  185. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/field_resolver.py +0 -0
  186. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/filters.py +0 -0
  187. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/hooks.py +0 -0
  188. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/inbound_webhooks.py +0 -0
  189. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/__init__.py +0 -0
  190. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/discovery.py +0 -0
  191. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/entities.py +0 -0
  192. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/interactions_v2.py +0 -0
  193. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/org.py +0 -0
  194. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/pagination.py +0 -0
  195. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/rate_limit_snapshot.py +0 -0
  196. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/relationships_v2.py +0 -0
  197. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/search.py +0 -0
  198. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/secondary.py +0 -0
  199. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/transcripts.py +0 -0
  200. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/types.py +0 -0
  201. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/policies.py +0 -0
  202. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/progress.py +0 -0
  203. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/py.typed +0 -0
  204. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/__init__.py +0 -0
  205. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_batch_interactions.py +0 -0
  206. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_discovery.py +0 -0
  207. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_dropdown_options.py +0 -0
  208. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_field_listing.py +0 -0
  209. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_field_updates.py +0 -0
  210. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_note_html.py +0 -0
  211. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_org_reads.py +0 -0
  212. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_search.py +0 -0
  213. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_single_field.py +0 -0
  214. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_v2_filters.py +0 -0
  215. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/companies.py +0 -0
  216. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/lists.py +0 -0
  217. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/opportunities.py +0 -0
  218. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/org.py +0 -0
  219. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/persons.py +0 -0
  220. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/rate_limits.py +0 -0
  221. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/reminders.py +0 -0
  222. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/search.py +0 -0
  223. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/tasks.py +0 -0
  224. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/transcripts.py +0 -0
  225. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/v1_only.py +0 -0
  226. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/webhooks.py +0 -0
  227. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/types.py +0 -0
  228. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/codecov.yml +0 -0
  229. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/cli-development-guide.md +0 -0
  230. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/ai-integrations/index.md +0 -0
  231. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/changelog.md +0 -0
  232. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/index.md +0 -0
  233. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/scripting.md +0 -0
  234. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli-reference.md +0 -0
  235. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/examples.md +0 -0
  236. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/getting-started.md +0 -0
  237. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/glossary.md +0 -0
  238. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/affinity-official-mcp-comparison.md +0 -0
  239. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/api-versions-and-routing.md +0 -0
  240. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/api-versions.md +0 -0
  241. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/authentication.md +0 -0
  242. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/claude-code-plugins.md +0 -0
  243. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/configuration.md +0 -0
  244. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/csv-export.md +0 -0
  245. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/datetime-handling.md +0 -0
  246. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/debugging-hooks.md +0 -0
  247. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/errors-and-retries.md +0 -0
  248. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/field-types-and-values.md +0 -0
  249. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/field-values.md +0 -0
  250. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/ids-and-types.md +0 -0
  251. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/migrating-to-2.md +0 -0
  252. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/models.md +0 -0
  253. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/opportunity-associations.md +0 -0
  254. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/pagination.md +0 -0
  255. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/performance.md +0 -0
  256. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/rate-limits.md +0 -0
  257. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/sync-vs-async.md +0 -0
  258. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/webhooks.md +0 -0
  259. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/index.md +0 -0
  260. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/mcp/index.md +0 -0
  261. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/api-coverage.md +0 -0
  262. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/client.md +0 -0
  263. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/exceptions.md +0 -0
  264. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/filters.md +0 -0
  265. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/models.md +0 -0
  266. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/companies.md +0 -0
  267. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/lists.md +0 -0
  268. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/opportunities.md +0 -0
  269. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/persons.md +0 -0
  270. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/reminders.md +0 -0
  271. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/tasks.md +0 -0
  272. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/teams-users.md +0 -0
  273. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/transcripts.md +0 -0
  274. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/auth.md +0 -0
  275. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/field-values.md +0 -0
  276. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/fields.md +0 -0
  277. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/files.md +0 -0
  278. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/interactions.md +0 -0
  279. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/notes.md +0 -0
  280. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/relationships.md +0 -0
  281. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/webhooks.md +0 -0
  282. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/types.md +0 -0
  283. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/troubleshooting.md +0 -0
  284. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/advanced_usage.py +0 -0
  285. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/async_lifecycle.py +0 -0
  286. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/basic_usage.py +0 -0
  287. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/filter_builder.py +0 -0
  288. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/hooks_debugging.py +0 -0
  289. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/list_management.py +0 -0
  290. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/resolve_helpers.py +0 -0
  291. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/task_polling.py +0 -0
  292. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/.gitignore +0 -0
  293. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +0 -0
  294. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/pipeline-history/SKILL.md +0 -0
  295. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/include-expand.md +0 -0
  296. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/output-formats.md +0 -0
  297. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/quantifiers.md +0 -0
  298. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/xaffinity-mcp.sh +0 -0
  299. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.gitignore +0 -0
  300. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/VERSION +0 -0
  301. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/bin/mcp-bash +0 -0
  302. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/completion.sh +0 -0
  303. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/lifecycle.sh +0 -0
  304. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/logging.sh +0 -0
  305. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/ping.sh +0 -0
  306. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/prompts.sh +0 -0
  307. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/resources.sh +0 -0
  308. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/roots.sh +0 -0
  309. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/tools.sh +0 -0
  310. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/auth.sh +0 -0
  311. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/capabilities.sh +0 -0
  312. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/common.sh +0 -0
  313. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/health.sh +0 -0
  314. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/completion.sh +0 -0
  315. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/core.sh +0 -0
  316. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/elicitation.sh +0 -0
  317. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/file_read.sh +0 -0
  318. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/handler_helpers.sh +0 -0
  319. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/hash.sh +0 -0
  320. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ids.sh +0 -0
  321. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/io.sh +0 -0
  322. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/json.sh +0 -0
  323. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/lock.sh +0 -0
  324. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/logging.sh +0 -0
  325. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/meta_env.sh +0 -0
  326. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/paginate.sh +0 -0
  327. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/path.sh +0 -0
  328. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/policy.sh +0 -0
  329. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress-passthrough.sh +0 -0
  330. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress.sh +0 -0
  331. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/prompts.sh +0 -0
  332. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/registry.sh +0 -0
  333. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/require.sh +0 -0
  334. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_content.sh +0 -0
  335. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_match.sh +0 -0
  336. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_providers.sh +0 -0
  337. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resources.sh +0 -0
  338. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/roots.sh +0 -0
  339. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/rpc.sh +0 -0
  340. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/runtime.sh +0 -0
  341. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/spec.sh +0 -0
  342. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/timeout.sh +0 -0
  343. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools.sh +0 -0
  344. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools_policy.sh +0 -0
  345. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui-templates.sh +0 -0
  346. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui.sh +0 -0
  347. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/uri.sh +0 -0
  348. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/validate.sh +0 -0
  349. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/echo.sh +0 -0
  350. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/file.sh +0 -0
  351. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/git.sh +0 -0
  352. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/https.sh +0 -0
  353. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/ui.sh +0 -0
  354. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-error.sh +0 -0
  355. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-sdk.sh +0 -0
  356. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/ui-sdk.sh +0 -0
  357. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/vendor.json +0 -0
  358. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/mcp-commands.json +0 -0
  359. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/prompts.json +0 -0
  360. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/resource-templates.json +0 -0
  361. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/resources.json +0 -0
  362. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/ui-resources.json +0 -0
  363. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/Makefile +0 -0
  364. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/README.md +0 -0
  365. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/entity-name.sh +0 -0
  366. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/list-name.sh +0 -0
  367. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/status-value.sh +0 -0
  368. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/docs/DEBUGGING.md +0 -0
  369. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/icon.svg +0 -0
  370. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cache.sh +0 -0
  371. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cli-detect.sh +0 -0
  372. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/common.sh +0 -0
  373. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/entity-types.sh +0 -0
  374. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/field-resolution.sh +0 -0
  375. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcp-bash.lock +0 -0
  376. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcp-publisher.lock +0 -0
  377. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcpb.conf +0 -0
  378. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.completion.sh +0 -0
  379. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.meta.json +0 -0
  380. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.txt +0 -0
  381. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.meta.json +0 -0
  382. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.txt +0 -0
  383. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.meta.json +0 -0
  384. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.txt +0 -0
  385. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +0 -0
  386. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +0 -0
  387. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.meta.json +0 -0
  388. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.txt +0 -0
  389. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.completion.sh +0 -0
  390. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.meta.json +0 -0
  391. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.txt +0 -0
  392. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +0 -0
  393. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.txt +0 -0
  394. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.meta.json +0 -0
  395. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.txt +0 -0
  396. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/providers/xaffinity.sh +0 -0
  397. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.meta.json +0 -0
  398. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.meta.json +0 -0
  399. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.sh +0 -0
  400. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.json +0 -0
  401. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.meta.json +0 -0
  402. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me/me.meta.json +0 -0
  403. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me/me.sh +0 -0
  404. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.meta.json +0 -0
  405. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.sh +0 -0
  406. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.meta.json +0 -0
  407. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.sh +0 -0
  408. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.meta.json +0 -0
  409. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.sh +0 -0
  410. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.meta.json +0 -0
  411. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.sh +0 -0
  412. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.meta.json +0 -0
  413. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.sh +0 -0
  414. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-field-catalogs.completion.sh +0 -0
  415. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-saved-views.completion.sh +0 -0
  416. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-workflow-config.completion.sh +0 -0
  417. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/env.sh +0 -0
  418. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/health-checks.sh +0 -0
  419. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/policy.sh +0 -0
  420. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.json +0 -0
  421. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/README.md +0 -0
  422. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/run.sh +0 -0
  423. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/test_env_update_check.sh +0 -0
  424. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test-progress.sh +0 -0
  425. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.meta.json +0 -0
  426. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.sh +0 -0
  427. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.sh +0 -0
  428. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.meta.json +0 -0
  429. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.sh +0 -0
  430. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.meta.json +0 -0
  431. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.sh +0 -0
  432. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.meta.json +0 -0
  433. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.sh +0 -0
  434. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/query/tool.sh +0 -0
  435. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.meta.json +0 -0
  436. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.sh +0 -0
  437. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/user-config.json +0 -0
  438. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp-env.sh +0 -0
  439. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp.sh +0 -0
  440. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mkdocs.yml +0 -0
  441. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/plugin.json +0 -0
  442. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +0 -0
  443. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/references/services.md +0 -0
  444. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/guard-env-read.sh +0 -0
  445. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/hooks.json +0 -0
  446. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/files-and-writes.md +0 -0
  447. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/history-and-activity.md +0 -0
  448. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/interactions.md +0 -0
  449. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/query/test_cursor.py +0 -0
  450. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_company_create_dedup.py +0 -0
  451. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_company_ls_filter_rejection.py +0 -0
  452. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_formatters.py +0 -0
  453. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_output_formats_integration.py +0 -0
  454. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_person_create_dedup.py +0 -0
  455. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_person_ls_filter_rejection.py +0 -0
  456. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_filter_rejection.py +0 -0
  457. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_list_entry_relationships.py +0 -0
  458. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_list_export_parity.py +0 -0
  459. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_output_flattening.py +0 -0
  460. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_output_truncation.py +0 -0
  461. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_unreplied.py +0 -0
  462. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/conftest.py +0 -0
  463. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/.cowork-redact.json +0 -0
  464. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/README.md +0 -0
  465. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/README.txt +0 -0
  466. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/xaffinity-test-key +0 -0
  467. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-nokey/README.txt +0 -0
  468. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/Dockerfile +0 -0
  469. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/build_fixtures.py +0 -0
  470. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/fixtures.json +0 -0
  471. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/server.py +0 -0
  472. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/xaffinity-wrapper.sh +0 -0
  473. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/privacy-allow.txt +0 -0
  474. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/record.sh +0 -0
  475. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/company-lists-status.yaml +0 -0
  476. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/hook-blocks-without-key.yaml +0 -0
  477. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/no-key-skill-path.yaml +0 -0
  478. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/status-history.yaml +0 -0
  479. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/sessions/no-key.yaml +0 -0
  480. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/sessions/with-key.yaml +0 -0
  481. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/field_write_mocks.py +0 -0
  482. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/openapi/mini_openapi.json +0 -0
  483. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/field_value_updated.json +0 -0
  484. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/list_entry_created.json +0 -0
  485. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_created.json +0 -0
  486. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_merged.json +0 -0
  487. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/person_created.json +0 -0
  488. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/unknown_event.json +0 -0
  489. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/README.md +0 -0
  490. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/conftest.py +0 -0
  491. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/setup_query_parity_data.py +0 -0
  492. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_cli_writes.py +0 -0
  493. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_query_parity_integration.py +0 -0
  494. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_reads.py +0 -0
  495. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes.py +0 -0
  496. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes_runner.py +0 -0
  497. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/mcp/__init__.py +0 -0
  498. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/mcp/test_query_cursor.py +0 -0
  499. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/skill-evals/xaffinity-cli-usage-evals/evals.json +0 -0
  500. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/spec_guard.py +0 -0
  501. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
  502. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_coverage.py +0 -0
  503. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_key_file_formats.py +0 -0
  504. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_key_resolution.py +0 -0
  505. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_version.py +0 -0
  506. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_version_per_operation.py +0 -0
  507. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_async_file_download_streaming.py +0 -0
  508. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_batch_get.py +0 -0
  509. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_api_version.py +0 -0
  510. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_column_limiting.py +0 -0
  511. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_command_context.py +0 -0
  512. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_commands_must_fix.py +0 -0
  513. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_company_cmds_coverage.py +0 -0
  514. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_company_get.py +0 -0
  515. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_config_cmds.py +0 -0
  516. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_context_coverage.py +0 -0
  517. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_csv_export.py +0 -0
  518. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_date_params.py +0 -0
  519. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_date_utils.py +0 -0
  520. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_datetime_formatting.py +0 -0
  521. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_datetime_header_offsets.py +0 -0
  522. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_domain_linkification.py +0 -0
  523. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_dotenv_resolution.py +0 -0
  524. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_dropdown_field_writes.py +0 -0
  525. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_enriched_field_writes.py +0 -0
  526. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_field_writes.py +0 -0
  527. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_files_dump.py +0 -0
  528. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field.py +0 -0
  529. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_batch_writes.py +0 -0
  530. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_multi_value_limits.py +0 -0
  531. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_error_hints.py +0 -0
  532. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_error_rendering.py +0 -0
  533. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history.py +0 -0
  534. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history_bulk.py +0 -0
  535. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history_deleted_options.py +0 -0
  536. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_options_and_transcripts.py +0 -0
  537. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils.py +0 -0
  538. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_coverage.py +0 -0
  539. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_set_phase.py +0 -0
  540. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_value_humanization.py +0 -0
  541. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_file_url.py +0 -0
  542. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_files_ls.py +0 -0
  543. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_files_read.py +0 -0
  544. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_get_interaction_dates.py +0 -0
  545. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_help_json.py +0 -0
  546. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_interaction_date_chunking.py +0 -0
  547. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_interaction_utils.py +0 -0
  548. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_json_safety.py +0 -0
  549. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_cmds_coverage.py +0 -0
  550. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_expand_interactions.py +0 -0
  551. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_entity_scope.py +0 -0
  552. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_field_refresh.py +0 -0
  553. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_filter_safety.py +0 -0
  554. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_truncation_meta.py +0 -0
  555. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_missing_coverage.py +0 -0
  556. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_multi_value_truncation_warnings.py +0 -0
  557. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_no_network_commands.py +0 -0
  558. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_notes_writes.py +0 -0
  559. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds.py +0 -0
  560. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds_coverage.py +0 -0
  561. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_org.py +0 -0
  562. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_page_size_validation.py +0 -0
  563. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_pager_logic.py +0 -0
  564. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_person_cmds_coverage.py +0 -0
  565. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_person_get.py +0 -0
  566. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_plugin_manifest.py +0 -0
  567. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_pre_xaffinity_hook.py +0 -0
  568. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_progress_manager.py +0 -0
  569. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_aggregates.py +0 -0
  570. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd.py +0 -0
  571. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd_coverage.py +0 -0
  572. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_dates.py +0 -0
  573. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_expand_interactions.py +0 -0
  574. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_filters.py +0 -0
  575. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_integration.py +0 -0
  576. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_must_fix.py +0 -0
  577. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_parser.py +0 -0
  578. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_planner.py +0 -0
  579. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_review_fixes.py +0 -0
  580. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_safety.py +0 -0
  581. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_schema.py +0 -0
  582. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_rendering.py +0 -0
  583. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_throttle.py +0 -0
  584. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_reminders.py +0 -0
  585. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_render_coverage.py +0 -0
  586. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_resolve_coverage.py +0 -0
  587. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_resolve_url_parsing.py +0 -0
  588. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_result_summary.py +0 -0
  589. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_safe_field_writes.py +0 -0
  590. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_search.py +0 -0
  591. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_serialization.py +0 -0
  592. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_session_cache.py +0 -0
  593. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_session_setup_hook.py +0 -0
  594. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_set_phase_atomicity.py +0 -0
  595. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_types.py +0 -0
  596. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_unreplied.py +0 -0
  597. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_update_check.py +0 -0
  598. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_v1_only_cmds.py +0 -0
  599. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_v1_parsing.py +0 -0
  600. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_webhooks.py +0 -0
  601. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_write_ops.py +0 -0
  602. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_client.py +0 -0
  603. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_companies_create_dedup.py +0 -0
  604. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_companies_filter_rejection.py +0 -0
  605. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_duplicates_connections.py +0 -0
  606. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_env_helpers.py +0 -0
  607. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_exceptions_coverage.py +0 -0
  608. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_resolver.py +0 -0
  609. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_service_caching.py +0 -0
  610. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_types_c4.py +0 -0
  611. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_value_type.py +0 -0
  612. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_values_get_value.py +0 -0
  613. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_batch_get.py +0 -0
  614. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_download_streaming.py +0 -0
  615. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_list_batch.py +0 -0
  616. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_upload_helpers_and_validation.py +0 -0
  617. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_files_upload_returning_files.py +0 -0
  618. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_files_v2.py +0 -0
  619. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_filters.py +0 -0
  620. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_generate_mcp_command_registry.py +0 -0
  621. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_fields_filter_includes.py +0 -0
  622. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_fields_pagination.py +0 -0
  623. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_first.py +0 -0
  624. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_hidden_field_values.py +0 -0
  625. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_hooks.py +0 -0
  626. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_http_client_additional_coverage.py +0 -0
  627. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_http_client_remaining_coverage.py +0 -0
  628. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_inbound_webhooks.py +0 -0
  629. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_integration_smoke.py +0 -0
  630. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_interaction_date_validation.py +0 -0
  631. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_interactions_and_files_regressions.py +0 -0
  632. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_isodatetime.py +0 -0
  633. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_entry_membership_and_opportunities.py +0 -0
  634. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_term.py +0 -0
  635. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_lists_v2_writes.py +0 -0
  636. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_bundle_env_and_completions.py +0 -0
  637. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_cli_version_check.py +0 -0
  638. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_entity_dossier.py +0 -0
  639. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_gateway_limits.py +0 -0
  640. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_history_bulk_gateway.py +0 -0
  641. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_limits.py +0 -0
  642. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_query_cli_error.py +0 -0
  643. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_read_truncation.py +0 -0
  644. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_resource_scripts.py +0 -0
  645. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_models.py +0 -0
  646. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_models_v2_2026_fields.py +0 -0
  647. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_multi_value_limits.py +0 -0
  648. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_new_features.py +0 -0
  649. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_notes_v2.py +0 -0
  650. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_notes_v2_writes.py +0 -0
  651. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_opportunities_filter_rejection.py +0 -0
  652. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_org_reads.py +0 -0
  653. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_pagination_iterators.py +0 -0
  654. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_persons_create_dedup.py +0 -0
  655. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_persons_filter_rejection.py +0 -0
  656. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_public_api.py +0 -0
  657. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_rate_limit_v2.py +0 -0
  658. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_raw_pipeline_hook_events.py +0 -0
  659. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_readonly_factory.py +0 -0
  660. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_reminder_list_batch.py +0 -0
  661. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_reminders_v2.py +0 -0
  662. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_requirements_additional.py +0 -0
  663. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_review_fixes_sdk_cli.py +0 -0
  664. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_sdk_interaction_dates.py +0 -0
  665. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_sdk_must_fix.py +0 -0
  666. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_search.py +0 -0
  667. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_search_v2.py +0 -0
  668. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_service_get_parameter_combinations.py +0 -0
  669. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_batch_get_interaction_dates.py +0 -0
  670. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_companies_coverage_gaps.py +0 -0
  671. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_dropdown_options.py +0 -0
  672. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_entity_field_updates.py +0 -0
  673. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_entity_list_entries.py +0 -0
  674. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_field_value_changes.py +0 -0
  675. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_list_entries_filter_paths.py +0 -0
  676. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_lists_additional_coverage.py +0 -0
  677. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_lists_coverage_gaps.py +0 -0
  678. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_additional_coverage.py +0 -0
  679. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_coverage_gaps.py +0 -0
  680. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
  681. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_pages_cursor_guard.py +0 -0
  682. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_persons_companies_additional_coverage.py +0 -0
  683. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_rate_limits_coverage_gaps.py +0 -0
  684. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_v1_only_async.py +0 -0
  685. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_v1_only_coverage_gaps.py +0 -0
  686. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_single_field_v2.py +0 -0
  687. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_small_modules_coverage.py +0 -0
  688. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_spec_guard.py +0 -0
  689. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_teams_users_feedback.py +0 -0
  690. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_transport_and_readonly_mode.py +0 -0
  691. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_association_parsing.py +0 -0
  692. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_only_services_additional_coverage.py +0 -0
  693. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_only_services_more_coverage.py +0 -0
  694. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v2_request_bodies.py +0 -0
  695. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_validate_openapi_tool.py +0 -0
  696. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_webhooks_v2.py +0 -0
  697. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/unit/__init__.py +0 -0
  698. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/unit/test_exceptions.py +0 -0
  699. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/__init__.py +0 -0
  700. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage.json +0 -0
  701. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage.py +0 -0
  702. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage_v1_snapshot.json +0 -0
  703. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/check_cli_patterns.py +0 -0
  704. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_mcp_command_registry.py +0 -0
  705. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_release_notes.py +0 -0
  706. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_requirements_mapping.py +0 -0
  707. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2024-01-01.json +0 -0
  708. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-07-15.json +0 -0
  709. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-09-17.json +0 -0
  710. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_bundle_env.py +0 -0
  711. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_registry.py +0 -0
  712. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_version.py +0 -0
  713. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/validate_mcp_registry_metadata.py +0 -0
  714. {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/validate_openapi_models.py +0 -0
@@ -5,6 +5,69 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.8] - 2026-11-05
9
+
10
+ **Exception to semantic versioning** (as 2.0.2–2.0.7): one fix changes which rows a filter
11
+ returns. It is marked **Behavior change**.
12
+
13
+ ### Highlights
14
+
15
+ Filters on a person or company field by id (`Owner = 12345`) now run on Affinity's side for list
16
+ entries, so `list export` needs no `--all` and downloads only the matching rows. A number on a
17
+ record reference is its id only.
18
+
19
+ ### Changed
20
+
21
+ - **Behavior change (correctness fix). CLI and SDK (`--filter`, `query`, `affinity.filters`,
22
+ `list(filter=...)`): an integer or 1–20 digits on a person, company or other record-reference
23
+ field matches the record's id only.** It no longer matches a record whose name is those digits;
24
+ use `starts_word` to find such a name. (As before, a reference with no name, such as a person
25
+ without a first and last name or a company with an empty name, can't be matched by id.)
26
+ - CLI and SDK: on list entries, `=` and `in` with record ids on a person or company field, and
27
+ `=`, `in`, `has_any` and `has_all` with ids on a multi-person or multi-company field, go to
28
+ Affinity's search. Such filters need no `--all` / `--max-results` and download only matching
29
+ rows. Ids above 2147483647, names, `!=`, enriched person and company fields, and filters on
30
+ `company ls` / `person ls` / `query` from companies or persons are still checked locally.
31
+ - CLI: a `starts_word` with no letter (`starts_word "360"`) is checked locally instead of being
32
+ sent as Affinity's name search. On `list export` it needs a scope flag; on `company ls`,
33
+ `person ls` and `query` from companies or persons it needs another field condition (or use
34
+ `--query`).
35
+
36
+ ### Fixed
37
+
38
+ - CLI: `list export --filter` with a filter Affinity's search refuses (for example a key without
39
+ the "Export data from Lists" permission), run without `--all`, `--max-results` or
40
+ `--first-page-only`, exits 2 before any output. It used to print only the first page, as if it
41
+ were the whole result. `details.refused` carries Affinity's reason.
42
+
43
+ ## [2.0.7] - 2026-11-03
44
+
45
+ **Exception to semantic versioning** (as 2.0.2–2.0.6): two fixes change which rows a filter
46
+ returns. Each is marked **Behavior change**.
47
+
48
+ ### Highlights
49
+
50
+ A repeated `--filter` now combines its conditions instead of keeping only the last one, and a
51
+ person or company field filtered by id (`Owner = 26229794`) matches that person instead of
52
+ nothing.
53
+
54
+ ### Changed
55
+
56
+ - **Behavior change (correctness fix). CLI: repeated `--filter` values are ANDed** on
57
+ `list export`, `company ls` and `person ls`, and so are repeated `list export --expand-filter`
58
+ values. Only the last one used to apply, and the others were dropped without a warning, so such
59
+ runs returned rows that didn't match the earlier conditions: re-run them. `--filter A --filter B`
60
+ is `(A) & (B)`; for OR, use `|` inside one value. Each repeated value must be a complete
61
+ expression on its own. (The MCP server refused a repeated `--filter`, so MCP calls weren't
62
+ affected.)
63
+ - **Behavior change (correctness fix). CLI and SDK: a person or company field compared with a
64
+ number matches the record's id.** `Owner = 26229794` (and `in`, `has_any`, `has_all`) in
65
+ `--filter`, `query` and `affinity.filters` compared the name with "26229794" and matched nothing,
66
+ without a warning (`!=` matched every row). It now matches that person's id, and names still
67
+ match as before. Other record references, such as lists, match their id too. Re-run filters that
68
+ used ids. A reference with no name (a person without a first and last name, a company with an
69
+ empty name) still can't be matched by id.
70
+
8
71
  ## [2.0.6] - 2026-10-14
9
72
 
10
73
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: affinity-sdk
3
- Version: 2.0.6
3
+ Version: 2.0.8
4
4
  Summary: A modern, strongly-typed Python SDK for the Affinity CRM API
5
5
  Project-URL: Homepage, https://github.com/yaniv-golan/affinity-sdk
6
6
  Project-URL: Documentation, https://yaniv-golan.github.io/affinity-sdk/latest/
@@ -21,12 +21,28 @@ from dataclasses import dataclass, field
21
21
  from datetime import date, datetime, timedelta
22
22
  from typing import Any
23
23
 
24
- from ..compare import compare_values
24
+ from ..compare import _as_entity_id, compare_values
25
25
  from ..criteria import Condition, FilterGroup, filter_value_type
26
26
  from ..models.entities import DropdownOption, FieldMetadata
27
27
  from .dates import parse_date_value
28
28
  from .where import WhereClause
29
29
 
30
+ # Person and company id conditions (list entries only): ``=`` / ``in`` on a single field,
31
+ # membership and set conditions on a multi field. Always in ALL_MAPPINGS, so the golden keeps
32
+ # testing them; only the pairs that passed it are in VERIFIED.
33
+ REFERENCE_MAPPINGS: frozenset[tuple[str, str]] = frozenset(
34
+ {
35
+ ("person", "is-any-of"),
36
+ ("company", "is-any-of"),
37
+ ("person-multi", "has-any-of"),
38
+ ("person-multi", "has-all-of"),
39
+ ("company-multi", "has-any-of"),
40
+ ("company-multi", "has-all-of"),
41
+ }
42
+ )
43
+ # Largest record id sent. Affinity's search refused ids above this in the golden run.
44
+ ID_MAX = 2**31 - 1
45
+
30
46
  # (filter value type, server operator) pairs confirmed by tools/search_golden.py: no record the
31
47
  # local filter keeps was missing from the server's answer (5 lists, about 3,750 entries,
32
48
  # 2026-10-13). Enriched fields and shared field names were excluded (they stay local).
@@ -84,8 +100,16 @@ VERIFIED: frozenset[tuple[str, str]] = frozenset(
84
100
  ("location", "is-not-empty"),
85
101
  ("location-multi", "is-empty"),
86
102
  ("location-multi", "is-not-empty"),
103
+ # Fifth run (person and company ids on list entries, 6 lists, about 12,300 entries,
104
+ # 2026-11-04; the single-company field on a list of its own, 12 cases): no record
105
+ # missing from the server's answer.
106
+ *REFERENCE_MAPPINGS,
87
107
  }
88
108
  )
109
+ # What goes to the company and person search endpoints: the golden run can only check list
110
+ # entries (the company directory can't be downloaded to compute an independent local set), so
111
+ # id conditions on person and company fields stay local there.
112
+ ENTITY_VERIFIED: frozenset[tuple[str, str]] = VERIFIED - REFERENCE_MAPPINGS
89
113
 
90
114
  _NUMBER_OPS = {
91
115
  "eq": "is-equal-to",
@@ -125,6 +149,7 @@ ALL_MAPPINGS: frozenset[tuple[str, str]] = frozenset(
125
149
  for op in ("has-any-of", "has-all-of", "has-none-of")
126
150
  }
127
151
  | {("number", "is-not-equal-to")}
152
+ | REFERENCE_MAPPINGS
128
153
  )
129
154
 
130
155
  _DROPDOWN = {"dropdown", "ranked-dropdown"}
@@ -232,12 +257,14 @@ def split_where(
232
257
 
233
258
  def _plain_term(value: Any) -> bool:
234
259
  """A name search term Affinity's search matches like ``starts_word``: letters, digits and
235
- spaces, 3+ characters (a term with punctuation, e.g. a placeholder name "- -", can match
236
- differently; golden test, 2026-10-13)."""
260
+ spaces, 3+ characters with at least one letter (a term with punctuation, e.g. a placeholder
261
+ name "- -", can match differently; golden test, 2026-10-13. A number is never sent: the
262
+ search may read it as a phone number or an id)."""
237
263
  return (
238
264
  isinstance(value, str)
239
265
  and re.fullmatch(r"[^\W_]+(?: [^\W_]+)*", value.strip()) is not None
240
266
  and len(value.strip()) >= 3
267
+ and any(c.isalpha() for c in value)
241
268
  )
242
269
 
243
270
 
@@ -338,17 +365,24 @@ def _field(w: WhereClause, ctx: _Ctx) -> tuple[FieldMetadata, str] | None:
338
365
  return meta, vt
339
366
 
340
367
 
341
- def _emit(
342
- w: WhereClause, meta: FieldMetadata, vt: str, op: str, value: Any, ctx: _Ctx
343
- ) -> Condition | None:
368
+ def _refused(w: WhereClause, meta: FieldMetadata, vt: str, op: str, ctx: _Ctx) -> bool:
369
+ """True (with the reason noted) when the pair isn't verified or the field doesn't take it."""
344
370
  if (vt, op) not in ctx.verified:
345
371
  ctx.local.append(f"{_describe(w)}: {vt} {op} not verified against the API yet")
346
- return None
372
+ return True
347
373
  allowed = [
348
374
  str(o.get("id")) for o in (meta.filterability or {}).get("operators") or [] if o.get("id")
349
375
  ]
350
376
  if "filterability" in meta.model_fields_set and allowed and op not in allowed:
351
377
  ctx.local.append(f"{_describe(w)}: the field doesn't take {op}")
378
+ return True
379
+ return False
380
+
381
+
382
+ def _emit(
383
+ w: WhereClause, meta: FieldMetadata, vt: str, op: str, value: Any, ctx: _Ctx
384
+ ) -> Condition | None:
385
+ if _refused(w, meta, vt, op, ctx):
352
386
  return None
353
387
  if isinstance(value, list) and not 1 <= len(value) <= MAX_VALUES:
354
388
  ctx.local.append(f"{_describe(w)}: needs 1 to {MAX_VALUES} values on the server")
@@ -399,8 +433,13 @@ def _condition(w: WhereClause, ctx: _Ctx) -> Condition | None:
399
433
  )
400
434
  return None
401
435
  if vt in _NAMED and op == "starts_word":
402
- ctx.local.append(f"{_describe(w)}: one name search per query (the rest stay local)")
436
+ if isinstance(value, str) and re.fullmatch(r"[0-9 ]+", value.strip()):
437
+ ctx.local.append(f"{_describe(w)}: a number isn't sent as a name search")
438
+ else:
439
+ ctx.local.append(f"{_describe(w)}: one name search per query (the rest stay local)")
403
440
  return None
441
+ if vt in _NAMED and op in ("eq", "in", "has_any", "has_all"):
442
+ return _reference(w, meta, vt, ctx)
404
443
  if vt in _DROPDOWN:
405
444
  return _dropdown(w, meta, vt, ctx)
406
445
  if vt in ("dropdown-multi", "filterable-text-multi"):
@@ -423,6 +462,63 @@ def _condition(w: WhereClause, ctx: _Ctx) -> Condition | None:
423
462
  return None
424
463
 
425
464
 
465
+ _NAMES_REASON = "names are matched locally (use the id to filter on Affinity's side)"
466
+
467
+
468
+ def _valid_ids(value: list[Any]) -> list[int] | str:
469
+ """The deduplicated record ids in ``value`` (order kept), or the reason they stay local:
470
+ any value that isn't id-shaped (a name) first, then any id outside ``1..ID_MAX``."""
471
+ ids = [_as_entity_id(v) for v in value]
472
+ if any(i is None for i in ids):
473
+ return _NAMES_REASON
474
+ valid = [i for i in ids if i is not None]
475
+ if any(not 1 <= i <= ID_MAX for i in valid):
476
+ return "not a valid record id"
477
+ return list(dict.fromkeys(valid))
478
+
479
+
480
+ def _reference_operator(op: str, value: Any, multi: bool) -> str | None:
481
+ """The server operator for a person or company condition, or ``None`` when none answers it
482
+ (locally ``in`` / ``has_any`` / ``has_all`` on a single field or with a scalar are False,
483
+ so pushing them would make the filter complete and return nothing)."""
484
+ as_list = isinstance(value, list)
485
+ if multi:
486
+ if (op in ("in", "has_any") and as_list) or (op == "eq" and not as_list):
487
+ return "has-any-of"
488
+ if op in ("has_all", "eq") and as_list:
489
+ return "has-all-of"
490
+ return None
491
+ if (op == "eq" and not as_list) or (op == "in" and as_list):
492
+ return "is-any-of"
493
+ return None
494
+
495
+
496
+ def _reference(w: WhereClause, meta: FieldMetadata, vt: str, ctx: _Ctx) -> Condition | None:
497
+ """Record ids on a person or company field: the server matches the id, the local filter
498
+ (which runs afterwards on every record) matches the id too (a number is an id only)."""
499
+ op, value = w.op or "", w.value
500
+ if meta.type == "enriched":
501
+ # Enriched values were never checked with these mappings, and search reads them
502
+ # differently from the entries API
503
+ ctx.local.append(f"{_describe(w)}: Affinity enriched fields stay local")
504
+ return None
505
+ server_op = None if value is None else _reference_operator(op, value, vt.endswith("-multi"))
506
+ if server_op is None:
507
+ ctx.local.append(f"{_describe(w)}: no server mapping for {vt} {op}")
508
+ return None
509
+ if _refused(w, meta, vt, server_op, ctx):
510
+ return None
511
+ items = value if isinstance(value, list) else [value]
512
+ if any(item is None for item in items):
513
+ ctx.local.append(f"{_describe(w)}: no server mapping for {vt} {op}")
514
+ return None
515
+ ids = _valid_ids(items)
516
+ if isinstance(ids, str):
517
+ ctx.local.append(f"{_describe(w)}: {ids}")
518
+ return None
519
+ return _emit(w, meta, vt, server_op, ids, ctx)
520
+
521
+
426
522
  def _dropdown(w: WhereClause, meta: FieldMetadata, vt: str, ctx: _Ctx) -> Condition | None:
427
523
  """Locally a dropdown value is the option's text, so map the text test onto option ids."""
428
524
  op, value = w.op, w.value
@@ -29,7 +29,12 @@ from ..entity_search import COMPANY_KEYS, filtered_ls
29
29
  from ..errors import CLIError
30
30
  from ..list_search import is_filter_cursor
31
31
  from ..mcp_limits import apply_mcp_limits
32
- from ..options import csv_output_options, csv_suboption_callback, output_options
32
+ from ..options import (
33
+ csv_output_options,
34
+ csv_suboption_callback,
35
+ join_filters_callback,
36
+ output_options,
37
+ )
33
38
  from ..progress import ProgressManager, ProgressSettings
34
39
  from ..resolve import get_company_fields, resolve_list_selector
35
40
  from ..resolvers import ResolvedEntity
@@ -330,9 +335,11 @@ def _parse_field_types(values: tuple[str, ...]) -> list[FieldType] | None:
330
335
  "--filter",
331
336
  "filter_expr",
332
337
  type=str,
333
- default=None,
338
+ multiple=True,
339
+ callback=join_filters_callback,
334
340
  help="Filter on company fields, applied by Affinity's search: 'field op value'. Ops: = != "
335
- "=~ =^ =$ > < >= <= starts_word. E.g., 'Stage = \"Seed\"'. Name search: --query.",
341
+ "=~ =^ =$ > < >= <= starts_word. E.g., 'Stage = \"Seed\"'. Name search: --query. "
342
+ "Repeatable: repeated values are ANDed.",
336
343
  )
337
344
  @click.option(
338
345
  "--query",
@@ -17,14 +17,15 @@ from affinity.exceptions import (
17
17
  AuthorizationError,
18
18
  ClientSideFilterWarning,
19
19
  NotFoundError,
20
+ UnsupportedOperationError,
20
21
  )
21
22
  from affinity.exceptions import ValidationError as SDKValidationError
22
23
  from affinity.filters import FilterExpression
23
24
  from affinity.filters import parse as parse_filter
24
25
  from affinity.models.entities import FieldMetadata, ListCreate, ListEntryWithEntity
25
- from affinity.models.pagination import FilterStats
26
+ from affinity.models.pagination import FilterStats, PaginatedResponse
26
27
  from affinity.models.types import InteractionType, ListType
27
- from affinity.services.lists import _entry_to_filter_dict
28
+ from affinity.services.lists import ListEntryService, _entry_to_filter_dict
28
29
  from affinity.types import (
29
30
  AnyFieldId,
30
31
  CompanyId,
@@ -44,7 +45,12 @@ from ..decorators import category, destructive
44
45
  from ..errors import CLIError
45
46
  from ..list_search import ListSearch, decode_cursor, encode_cursor, plan_list_search
46
47
  from ..mcp_limits import apply_mcp_limits
47
- from ..options import csv_output_options, csv_suboption_callback, output_options
48
+ from ..options import (
49
+ csv_output_options,
50
+ csv_suboption_callback,
51
+ join_filters_callback,
52
+ output_options,
53
+ )
48
54
  from ..render import format_duration
49
55
  from ..resolve import (
50
56
  list_all_saved_views,
@@ -452,9 +458,10 @@ ExpandOnError = Literal["raise", "skip"]
452
458
  "--filter",
453
459
  "filter_expr",
454
460
  type=str,
455
- default=None,
461
+ multiple=True,
462
+ callback=join_filters_callback,
456
463
  help="Filter (field op value): Affinity's search applies what it can, the rest is checked "
457
- 'locally. Quote multi-word: Status="Intro Meeting".',
464
+ 'locally. Quote multi-word: Status="Intro Meeting". Repeatable: repeated values are ANDed.',
458
465
  )
459
466
  @click.option(
460
467
  "--page-size",
@@ -570,8 +577,10 @@ ExpandOnError = Literal["raise", "skip"]
570
577
  "--expand-filter",
571
578
  "expand_filter",
572
579
  type=str,
573
- default=None,
574
- help="Filter expanded entities (e.g., 'field=value' or 'field!=value').",
580
+ multiple=True,
581
+ callback=join_filters_callback,
582
+ help="Filter expanded entities (e.g., 'field=value' or 'field!=value'). "
583
+ "Repeatable: repeated values are ANDed.",
575
584
  )
576
585
  @click.option(
577
586
  "--expand-opportunities-list",
@@ -1141,6 +1150,33 @@ def list_export(
1141
1150
  api_called=True,
1142
1151
  )
1143
1152
 
1153
+ # Open Affinity's search here, before any output: a refusal must not surface halfway
1154
+ # through a CSV (its header is already written) or leave a silent first page.
1155
+ search_body: dict[str, Any] | None = list_search.body if list_search else None
1156
+ opened_page: PaginatedResponse[ListEntryWithEntity] | None = None
1157
+ if search_body is not None and filter_expr and not saved_view and cursor is None:
1158
+ try:
1159
+ opened_page = _open_search(
1160
+ client.lists.entries(list_id),
1161
+ search_body,
1162
+ list(dict.fromkeys([*selected_field_ids, *filter_field_ids])),
1163
+ page_size,
1164
+ )
1165
+ except (
1166
+ AuthorizationError,
1167
+ NotFoundError,
1168
+ SDKValidationError,
1169
+ UnsupportedOperationError,
1170
+ ) as e:
1171
+ if not (all_pages or max_results is not None or first_page_only):
1172
+ raise _filter_scope_error(
1173
+ filter_expr, list_search.local if list_search else [], reason=str(e)
1174
+ ) from e
1175
+ warnings.append(f"Affinity's search refused the filter, filtering locally: {e}")
1176
+ if server_filter is not None:
1177
+ server_filter["fallback"] = e.message
1178
+ search_body = None
1179
+
1144
1180
  # Build expand field data structures from parsed_expand_fields
1145
1181
  # - expand_field_ids: list of field IDs for API calls
1146
1182
  # - field_id_to_display: dict mapping field ID (str) -> display name (original spec)
@@ -1330,7 +1366,8 @@ def list_export(
1330
1366
  state=csv_iter_state,
1331
1367
  cache=cache,
1332
1368
  filter_progress_callback=filter_callback,
1333
- search=list_search.body if list_search else None,
1369
+ search=search_body,
1370
+ opened_page=opened_page,
1334
1371
  filter_field_ids=filter_field_ids,
1335
1372
  ):
1336
1373
  next_cursor = page_next_cursor
@@ -1656,7 +1693,6 @@ def list_export(
1656
1693
  # only reach the JSON envelope, which CSV never builds.
1657
1694
  for msg in [
1658
1695
  *warnings,
1659
- *csv_iter_state.get("warnings", []),
1660
1696
  *truncation_warnings(
1661
1697
  csv_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
1662
1698
  ),
@@ -1768,7 +1804,8 @@ def list_export(
1768
1804
  state=table_iter_state,
1769
1805
  cache=cache,
1770
1806
  filter_progress_callback=json_filter_callback,
1771
- search=list_search.body if list_search else None,
1807
+ search=search_body,
1808
+ opened_page=opened_page,
1772
1809
  filter_field_ids=filter_field_ids,
1773
1810
  ):
1774
1811
  next_cursor = page_next_cursor
@@ -1911,9 +1948,6 @@ def list_export(
1911
1948
  warnings.append("Results limited by --max-results. Use --all to fetch all results.")
1912
1949
  from ..field_utils import truncation_warnings
1913
1950
 
1914
- warnings.extend(table_iter_state.get("warnings", []))
1915
- if server_filter is not None and table_iter_state.get("searchFallback"):
1916
- server_filter["fallback"] = table_iter_state["searchFallback"]
1917
1951
  warnings.extend(
1918
1952
  truncation_warnings(
1919
1953
  table_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
@@ -2107,6 +2141,7 @@ def _iterate_list_entries(
2107
2141
  cache: Any = None,
2108
2142
  filter_progress_callback: Callable[[FilterStats], None] | None = None,
2109
2143
  search: dict[str, Any] | None = None,
2144
+ opened_page: PaginatedResponse[ListEntryWithEntity] | None = None,
2110
2145
  filter_field_ids: list[str] | None = None,
2111
2146
  ) -> Any:
2112
2147
  """
@@ -2188,38 +2223,27 @@ def _iterate_list_entries(
2188
2223
  else None
2189
2224
  )
2190
2225
  if decoded is not None or (search is not None and filter_expr):
2191
- try:
2192
- if decoded is not None:
2193
- assert decoded.body is not None
2194
- body, local_filter = decoded.body, decoded.filter
2195
- first = entries.find_body(body, cursor=decoded.url)
2196
- else:
2197
- assert search is not None and filter_expr
2198
- body, local_filter = search, parse_filter(filter_expr)
2199
- first = entries.find_body(body, field_ids=fetch_ids, limit=page_size)
2200
- except (AuthorizationError, NotFoundError, SDKValidationError) as e:
2201
- if decoded is not None:
2202
- raise
2203
- if state is not None:
2204
- state.setdefault("warnings", []).append(
2205
- f"Affinity's search refused the filter, filtering locally: {e}"
2206
- )
2207
- state["searchFallback"] = getattr(e, "message", None) or str(e)
2226
+ if decoded is not None:
2227
+ assert decoded.body is not None
2228
+ body, local_filter = decoded.body, decoded.filter
2229
+ first = entries.find_body(body, cursor=decoded.url)
2208
2230
  else:
2209
- yield from _search_rows(
2210
- entries,
2211
- first,
2212
- body=body,
2213
- local_filter=local_filter,
2214
- selected_field_ids=selected_field_ids,
2215
- field_by_id=field_by_id,
2216
- key_mode=key_mode,
2217
- max_results=max_results,
2218
- all_pages=all_pages,
2219
- state=state,
2220
- filter_progress_callback=filter_progress_callback,
2221
- )
2222
- return
2231
+ assert search is not None and filter_expr and opened_page is not None
2232
+ body, local_filter, first = search, parse_filter(filter_expr), opened_page
2233
+ yield from _search_rows(
2234
+ entries,
2235
+ first,
2236
+ body=body,
2237
+ local_filter=local_filter,
2238
+ selected_field_ids=selected_field_ids,
2239
+ field_by_id=field_by_id,
2240
+ key_mode=key_mode,
2241
+ max_results=max_results,
2242
+ all_pages=all_pages,
2243
+ state=state,
2244
+ filter_progress_callback=filter_progress_callback,
2245
+ )
2246
+ return
2223
2247
 
2224
2248
  pages = (
2225
2249
  entries.pages(cursor=cursor)
@@ -2292,17 +2316,39 @@ def _filter_names_list_fields(filter_expr: str) -> bool:
2292
2316
  return False
2293
2317
 
2294
2318
 
2295
- def _filter_scope_error(filter_expr: str, local: list[str]) -> CLIError:
2296
- return CLIError(
2297
- "Part of this --filter runs locally on fetched pages, so without a scope flag the "
2298
- "export would silently return only first-page matches. Add --all to scan everything, "
2299
- "--max-results N to cap, or --first-page-only to opt in.",
2300
- exit_code=2,
2301
- error_type="usage_error",
2302
- hint="details.local names the conditions Affinity's search can't apply; --saved-view "
2303
- "filters large lists on Affinity's side.",
2304
- details={"rejected_filter": str(filter_expr), "local": local},
2319
+ def _open_search(
2320
+ entries: ListEntryService,
2321
+ body: dict[str, Any],
2322
+ field_ids: list[str],
2323
+ page_size: int,
2324
+ ) -> PaginatedResponse[ListEntryWithEntity]:
2325
+ """First page of Affinity's list entry search (raises when Affinity refuses the filter)."""
2326
+ return entries.find_body(body, field_ids=field_ids, limit=page_size)
2327
+
2328
+
2329
+ def _filter_scope_error(filter_expr: str, local: list[str], reason: str | None = None) -> CLIError:
2330
+ scope_flags = (
2331
+ "Add --all to scan everything, --max-results N to cap, or --first-page-only to opt in."
2305
2332
  )
2333
+ if reason is None:
2334
+ message = (
2335
+ "Part of this --filter runs locally on fetched pages, so without a scope flag the "
2336
+ f"export would silently return only first-page matches. {scope_flags}"
2337
+ )
2338
+ hint = (
2339
+ "details.local names the conditions Affinity's search can't apply; --saved-view "
2340
+ "filters large lists on Affinity's side."
2341
+ )
2342
+ details: dict[str, Any] = {"rejected_filter": str(filter_expr), "local": local}
2343
+ else:
2344
+ message = (
2345
+ f"Affinity's search refused this --filter ({reason}), so it would run locally on "
2346
+ "fetched pages, and without a scope flag the export would silently return only "
2347
+ f"first-page matches. {scope_flags}"
2348
+ )
2349
+ hint = "Affinity refused the search; add --all or --max-results to filter locally."
2350
+ details = {"rejected_filter": str(filter_expr), "local": local, "refused": reason}
2351
+ return CLIError(message, exit_code=2, error_type="usage_error", hint=hint, details=details)
2306
2352
 
2307
2353
 
2308
2354
  def _search_rows(
@@ -27,7 +27,12 @@ from ..entity_search import PERSON_KEYS, filtered_ls
27
27
  from ..errors import CLIError
28
28
  from ..list_search import is_filter_cursor
29
29
  from ..mcp_limits import apply_mcp_limits
30
- from ..options import csv_output_options, csv_suboption_callback, output_options
30
+ from ..options import (
31
+ csv_output_options,
32
+ csv_suboption_callback,
33
+ join_filters_callback,
34
+ output_options,
35
+ )
31
36
  from ..progress import ProgressManager, ProgressSettings
32
37
  from ..resolve import get_person_fields, resolve_list_selector
33
38
  from ..resolvers import ResolvedEntity
@@ -207,9 +212,11 @@ def _parse_field_types(values: tuple[str, ...]) -> list[FieldType] | None:
207
212
  "--filter",
208
213
  "filter_expr",
209
214
  type=str,
210
- default=None,
215
+ multiple=True,
216
+ callback=join_filters_callback,
211
217
  help="Filter on person fields, applied by Affinity's search: 'field op value'. Ops: = != "
212
- "=~ =^ =$ > < >= <= starts_word. E.g., 'Deals > 5'. Name/email search: --query.",
218
+ "=~ =^ =$ > < >= <= starts_word. E.g., 'Deals > 5'. Name/email search: --query. "
219
+ "Repeatable: repeated values are ANDed.",
213
220
  )
214
221
  @click.option(
215
222
  "--query",
@@ -21,7 +21,7 @@ from affinity.filters import FilterExpression
21
21
  from affinity.services._search import SEARCH_INCLUDES
22
22
 
23
23
  from .query.models import WhereClause
24
- from .query.pushdown import fields_index, split_where
24
+ from .query.pushdown import ENTITY_VERIFIED, fields_index, split_where
25
25
 
26
26
  # Record attributes (not fields) a company or person filter can test.
27
27
  COMPANY_KEYS = frozenset({"id", "name", "domain", "domains"})
@@ -57,7 +57,7 @@ def plan_entity_search(service: Any, where: WhereClause) -> EntitySearch:
57
57
  options[key] = list(service.get_field_dropdown_options(meta.id))
58
58
  return options[key]
59
59
 
60
- split = split_where(where, fields, options_for, enriched="as-is")
60
+ split = split_where(where, fields, options_for, verified=ENTITY_VERIFIED, enriched="as-is")
61
61
  index = fields_index(fields)
62
62
  field_ids = sorted(
63
63
  {
@@ -94,7 +94,8 @@ def _paths(where: WhereClause) -> set[str]:
94
94
 
95
95
  def entity_filter_dict(entity: Any) -> dict[str, Any]:
96
96
  """What a ``--filter`` on companies or persons sees: field values by name (dropdowns as
97
- text, persons and companies as names) plus the record's own attributes."""
97
+ text, persons and companies as names; a number in a filter matches their id) plus the
98
+ record's own attributes."""
98
99
  result: dict[str, Any] = {}
99
100
  by_id: dict[str, Any] = {}
100
101
  for item in getattr(entity, "fields_raw", None) or []:
@@ -4,6 +4,8 @@ import functools
4
4
  from collections.abc import Callable
5
5
  from typing import Any, TypeVar, cast
6
6
 
7
+ from affinity.filters import parse
8
+
7
9
  from .click_compat import click
8
10
  from .context import CLIContext, OutputFormat
9
11
  from .errors import CLIError
@@ -143,6 +145,28 @@ def _emit_validation_error(ctx: CLIContext, err: CLIError) -> None:
143
145
  sys.stderr.write(f"Hint: {err.hint}\n")
144
146
 
145
147
 
148
+ def join_filters_callback(
149
+ _ctx: click.Context, _param: click.Parameter, value: tuple[str, ...]
150
+ ) -> str | None:
151
+ """Callback for a repeatable filter option (--filter, --expand-filter): AND the values.
152
+
153
+ One value is passed on unchanged. Repeated values are each parsed on their own first, so a
154
+ value can't close the parentheses it is wrapped in, and its error names it.
155
+ """
156
+ if not value:
157
+ return None
158
+ if len(value) == 1:
159
+ return value[0]
160
+ for i, text in enumerate(value, 1):
161
+ if not text.strip():
162
+ raise click.BadParameter(f"value {i} is empty; each repeated value needs an expression")
163
+ try:
164
+ parse(text)
165
+ except ValueError as e:
166
+ raise click.BadParameter(f"value {i} ({text!r}): {e}") from e
167
+ return " & ".join(f"({text})" for text in value)
168
+
169
+
146
170
  def csv_suboption_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
147
171
  """Callback for CSV-related sub-options (--csv-bom, --csv-header, --csv-mode).
148
172