affinity-sdk 2.0.7__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 (715) hide show
  1. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/CHANGELOG.md +35 -0
  2. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/PKG-INFO +1 -1
  3. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/pushdown.py +104 -8
  4. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/list_cmds.py +87 -49
  5. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/entity_search.py +4 -4
  6. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/executor.py +9 -3
  7. affinity_sdk-2.0.8/affinity/cli/query/pushdown.py +25 -0
  8. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/compare.py +15 -9
  9. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/cli/commands.md +3 -3
  10. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/filtering.md +24 -14
  11. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/query-command.md +4 -4
  12. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/query-language.md +2 -2
  13. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/plugin.json +1 -1
  14. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/SKILL.md +4 -4
  15. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/filter-operators.md +1 -1
  16. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/commands.generated.json +2 -2
  17. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/CHANGELOG.md +17 -0
  18. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/COMPATIBILITY +8 -2
  19. affinity_sdk-2.0.8/mcp/VERSION +1 -0
  20. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.md +4 -4
  21. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.d/requirements.json +1 -1
  22. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.d/server.meta.json +1 -1
  23. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.meta.json +1 -1
  24. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/query/tool.meta.json +1 -1
  25. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/.claude-plugin/plugin.json +1 -1
  26. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/pre-xaffinity.sh +2 -2
  27. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/session-setup.sh +1 -1
  28. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/SKILL.md +2 -2
  29. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/filtering.md +14 -7
  30. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/query-guide.md +15 -8
  31. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/setup.md +1 -1
  32. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/pyproject.toml +1 -1
  33. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/cassettes/company-lists-status.cassette.json +89 -89
  34. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/cassettes/hook-blocks-without-key.cassette.json +66 -66
  35. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/cassettes/no-key-skill-path.cassette.json +105 -104
  36. affinity_sdk-2.0.8/tests/cowork/cassettes/status-history.cassette.json +469 -0
  37. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entity_ls_server_filter.py +87 -0
  38. affinity_sdk-2.0.8/tests/test_cli_list_export_server_filter.py +661 -0
  39. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_executor.py +8 -2
  40. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_server_filter.py +191 -5
  41. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_compare.py +1 -1
  42. affinity_sdk-2.0.8/tests/test_compare_entity_ids.py +159 -0
  43. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_list_entries_server_filter.py +81 -1
  44. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_query_pushdown.py +231 -1
  45. affinity_sdk-2.0.8/tools/search_golden.py +478 -0
  46. affinity_sdk-2.0.7/affinity/cli/query/pushdown.py +0 -12
  47. affinity_sdk-2.0.7/mcp/VERSION +0 -1
  48. affinity_sdk-2.0.7/tests/cowork/cassettes/status-history.cassette.json +0 -462
  49. affinity_sdk-2.0.7/tests/test_cli_list_export_server_filter.py +0 -336
  50. affinity_sdk-2.0.7/tests/test_compare_entity_ids.py +0 -102
  51. affinity_sdk-2.0.7/tools/search_golden.py +0 -238
  52. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.claude-plugin/marketplace.json +0 -0
  53. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.cursor/rules/test-data-privacy.mdc +0 -0
  54. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.editorconfig +0 -0
  55. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.env.example +0 -0
  56. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.gitattributes +0 -0
  57. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/CODEOWNERS +0 -0
  58. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  59. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  60. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
  61. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/release.md +0 -0
  62. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/dependabot.yml +0 -0
  63. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/labels.yml +0 -0
  64. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/mcp-release-install-footer.md +0 -0
  65. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/pull_request_template.md +0 -0
  66. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/release-install-footer.md +0 -0
  67. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/ci.yml +0 -0
  68. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/cowork-replay.yml +0 -0
  69. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/docs.yml +0 -0
  70. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/labels.yml +0 -0
  71. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/linkcheck.yml +0 -0
  72. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/openapi-validation.yml +0 -0
  73. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/plugin-build.yml +0 -0
  74. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/plugin-release.yml +0 -0
  75. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/release-detect.yml +0 -0
  76. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/release.yml +0 -0
  77. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.github/workflows/version-check.yml +0 -0
  78. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.gitignore +0 -0
  79. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/.pre-commit-config.yaml +0 -0
  80. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/AGENTS.md +0 -0
  81. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/CODE_OF_CONDUCT.md +0 -0
  82. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/CONTRIBUTING.md +0 -0
  83. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/LICENSE +0 -0
  84. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/README.md +0 -0
  85. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/SECURITY.md +0 -0
  86. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/VERSIONING.md +0 -0
  87. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/__init__.py +0 -0
  88. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/__init__.py +0 -0
  89. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/dates.py +0 -0
  90. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/filter_text.py +0 -0
  91. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/search.py +0 -0
  92. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_filtering/where.py +0 -0
  93. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_internal/__init__.py +0 -0
  94. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/_internal/keyfile.py +0 -0
  95. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/api_versions.py +0 -0
  96. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/__init__.py +0 -0
  97. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/__main__.py +0 -0
  98. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/_update_worker.py +0 -0
  99. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/async_utils.py +0 -0
  100. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/click_compat.py +0 -0
  101. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/__init__.py +0 -0
  102. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_field.py +0 -0
  103. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_dump.py +0 -0
  104. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_read.py +0 -0
  105. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_upload.py +0 -0
  106. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_list_entry_fields.py +0 -0
  107. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_org_reads.py +0 -0
  108. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_search_common.py +0 -0
  109. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/_v1_parsing.py +0 -0
  110. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/company_cmds.py +0 -0
  111. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/completion_cmd.py +0 -0
  112. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/config_cmds.py +0 -0
  113. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/discovery_cmds.py +0 -0
  114. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/entry_cmds.py +0 -0
  115. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/field_cmds.py +0 -0
  116. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/file_cmds.py +0 -0
  117. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/file_url_cmd.py +0 -0
  118. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/interaction_cmds.py +0 -0
  119. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/note_cmds.py +0 -0
  120. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/opportunity_cmds.py +0 -0
  121. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/org_cmds.py +0 -0
  122. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/org_read_cmds.py +0 -0
  123. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/person_cmds.py +0 -0
  124. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/query_cmd.py +0 -0
  125. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/relationship_strength_cmds.py +0 -0
  126. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/reminder_cmds.py +0 -0
  127. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/resolve_url_cmd.py +0 -0
  128. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/session_cmds.py +0 -0
  129. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/task_cmds.py +0 -0
  130. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/transcript_cmds.py +0 -0
  131. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/version_cmd.py +0 -0
  132. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/webhook_cmds.py +0 -0
  133. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/commands/whoami_cmd.py +0 -0
  134. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/config.py +0 -0
  135. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/confirm.py +0 -0
  136. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/constants.py +0 -0
  137. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/context.py +0 -0
  138. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/csv_utils.py +0 -0
  139. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/date_utils.py +0 -0
  140. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/decorators.py +0 -0
  141. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/errors.py +0 -0
  142. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/field_utils.py +0 -0
  143. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/formatters.py +0 -0
  144. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/help_json.py +0 -0
  145. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/interaction_utils.py +0 -0
  146. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/list_search.py +0 -0
  147. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/logging.py +0 -0
  148. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/main.py +0 -0
  149. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/mcp_limits.py +0 -0
  150. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/options.py +0 -0
  151. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/paths.py +0 -0
  152. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/progress.py +0 -0
  153. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/__init__.py +0 -0
  154. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/aggregates.py +0 -0
  155. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/cursor.py +0 -0
  156. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/dates.py +0 -0
  157. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/exceptions.py +0 -0
  158. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/filter_text.py +0 -0
  159. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/filters.py +0 -0
  160. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/models.py +0 -0
  161. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/output.py +0 -0
  162. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/parser.py +0 -0
  163. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/planner.py +0 -0
  164. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/progress.py +0 -0
  165. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/query/schema.py +0 -0
  166. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/render.py +0 -0
  167. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/resolve.py +0 -0
  168. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/resolvers.py +0 -0
  169. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/results.py +0 -0
  170. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/runner.py +0 -0
  171. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/serialization.py +0 -0
  172. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/session_cache.py +0 -0
  173. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/types.py +0 -0
  174. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/cli/update_check.py +0 -0
  175. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/client.py +0 -0
  176. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/clients/__init__.py +0 -0
  177. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/clients/http.py +0 -0
  178. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/clients/pipeline.py +0 -0
  179. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/criteria.py +0 -0
  180. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/downloads.py +0 -0
  181. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/exceptions.py +0 -0
  182. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/field_resolve_utils.py +0 -0
  183. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/field_resolver.py +0 -0
  184. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/filters.py +0 -0
  185. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/hooks.py +0 -0
  186. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/inbound_webhooks.py +0 -0
  187. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/__init__.py +0 -0
  188. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/discovery.py +0 -0
  189. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/entities.py +0 -0
  190. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/interactions_v2.py +0 -0
  191. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/org.py +0 -0
  192. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/pagination.py +0 -0
  193. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/rate_limit_snapshot.py +0 -0
  194. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/relationships_v2.py +0 -0
  195. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/search.py +0 -0
  196. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/secondary.py +0 -0
  197. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/transcripts.py +0 -0
  198. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/models/types.py +0 -0
  199. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/policies.py +0 -0
  200. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/progress.py +0 -0
  201. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/py.typed +0 -0
  202. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/__init__.py +0 -0
  203. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_batch_interactions.py +0 -0
  204. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_discovery.py +0 -0
  205. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_dropdown_options.py +0 -0
  206. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_field_listing.py +0 -0
  207. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_field_updates.py +0 -0
  208. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_note_html.py +0 -0
  209. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_org_reads.py +0 -0
  210. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_search.py +0 -0
  211. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_single_field.py +0 -0
  212. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/_v2_filters.py +0 -0
  213. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/companies.py +0 -0
  214. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/lists.py +0 -0
  215. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/opportunities.py +0 -0
  216. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/org.py +0 -0
  217. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/persons.py +0 -0
  218. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/rate_limits.py +0 -0
  219. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/reminders.py +0 -0
  220. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/search.py +0 -0
  221. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/tasks.py +0 -0
  222. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/transcripts.py +0 -0
  223. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/v1_only.py +0 -0
  224. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/services/webhooks.py +0 -0
  225. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/affinity/types.py +0 -0
  226. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/codecov.yml +0 -0
  227. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/cli-development-guide.md +0 -0
  228. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/ai-integrations/index.md +0 -0
  229. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/changelog.md +0 -0
  230. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/cli/index.md +0 -0
  231. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/cli/scripting.md +0 -0
  232. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/cli-reference.md +0 -0
  233. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/examples.md +0 -0
  234. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/getting-started.md +0 -0
  235. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/glossary.md +0 -0
  236. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/affinity-official-mcp-comparison.md +0 -0
  237. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/api-versions-and-routing.md +0 -0
  238. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/api-versions.md +0 -0
  239. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/authentication.md +0 -0
  240. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/claude-code-plugins.md +0 -0
  241. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/configuration.md +0 -0
  242. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/csv-export.md +0 -0
  243. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/datetime-handling.md +0 -0
  244. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/debugging-hooks.md +0 -0
  245. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/errors-and-retries.md +0 -0
  246. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/field-types-and-values.md +0 -0
  247. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/field-values.md +0 -0
  248. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/ids-and-types.md +0 -0
  249. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/migrating-to-2.md +0 -0
  250. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/models.md +0 -0
  251. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/opportunity-associations.md +0 -0
  252. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/pagination.md +0 -0
  253. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/performance.md +0 -0
  254. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/rate-limits.md +0 -0
  255. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/sync-vs-async.md +0 -0
  256. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/guides/webhooks.md +0 -0
  257. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/index.md +0 -0
  258. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/mcp/index.md +0 -0
  259. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/api-coverage.md +0 -0
  260. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/client.md +0 -0
  261. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/exceptions.md +0 -0
  262. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/filters.md +0 -0
  263. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/models.md +0 -0
  264. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/companies.md +0 -0
  265. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/lists.md +0 -0
  266. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/opportunities.md +0 -0
  267. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/persons.md +0 -0
  268. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/reminders.md +0 -0
  269. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/tasks.md +0 -0
  270. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/teams-users.md +0 -0
  271. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/transcripts.md +0 -0
  272. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/auth.md +0 -0
  273. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/field-values.md +0 -0
  274. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/fields.md +0 -0
  275. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/files.md +0 -0
  276. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/interactions.md +0 -0
  277. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/notes.md +0 -0
  278. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/relationships.md +0 -0
  279. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/services/webhooks.md +0 -0
  280. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/reference/types.md +0 -0
  281. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/docs/public/troubleshooting.md +0 -0
  282. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/advanced_usage.py +0 -0
  283. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/async_lifecycle.py +0 -0
  284. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/basic_usage.py +0 -0
  285. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/filter_builder.py +0 -0
  286. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/hooks_debugging.py +0 -0
  287. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/list_management.py +0 -0
  288. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/resolve_helpers.py +0 -0
  289. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/examples/task_polling.py +0 -0
  290. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/.gitignore +0 -0
  291. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +0 -0
  292. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/pipeline-history/SKILL.md +0 -0
  293. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/include-expand.md +0 -0
  294. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/output-formats.md +0 -0
  295. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/quantifiers.md +0 -0
  296. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.claude-plugin/xaffinity-mcp.sh +0 -0
  297. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.gitignore +0 -0
  298. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/VERSION +0 -0
  299. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/bin/mcp-bash +0 -0
  300. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/completion.sh +0 -0
  301. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/lifecycle.sh +0 -0
  302. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/logging.sh +0 -0
  303. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/ping.sh +0 -0
  304. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/prompts.sh +0 -0
  305. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/resources.sh +0 -0
  306. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/roots.sh +0 -0
  307. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/tools.sh +0 -0
  308. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/auth.sh +0 -0
  309. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/capabilities.sh +0 -0
  310. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/common.sh +0 -0
  311. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/health.sh +0 -0
  312. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/completion.sh +0 -0
  313. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/core.sh +0 -0
  314. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/elicitation.sh +0 -0
  315. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/file_read.sh +0 -0
  316. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/handler_helpers.sh +0 -0
  317. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/hash.sh +0 -0
  318. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ids.sh +0 -0
  319. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/io.sh +0 -0
  320. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/json.sh +0 -0
  321. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/lock.sh +0 -0
  322. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/logging.sh +0 -0
  323. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/meta_env.sh +0 -0
  324. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/paginate.sh +0 -0
  325. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/path.sh +0 -0
  326. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/policy.sh +0 -0
  327. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress-passthrough.sh +0 -0
  328. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress.sh +0 -0
  329. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/prompts.sh +0 -0
  330. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/registry.sh +0 -0
  331. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/require.sh +0 -0
  332. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_content.sh +0 -0
  333. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_match.sh +0 -0
  334. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_providers.sh +0 -0
  335. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resources.sh +0 -0
  336. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/roots.sh +0 -0
  337. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/rpc.sh +0 -0
  338. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/runtime.sh +0 -0
  339. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/spec.sh +0 -0
  340. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/timeout.sh +0 -0
  341. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools.sh +0 -0
  342. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools_policy.sh +0 -0
  343. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui-templates.sh +0 -0
  344. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui.sh +0 -0
  345. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/uri.sh +0 -0
  346. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/validate.sh +0 -0
  347. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/echo.sh +0 -0
  348. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/file.sh +0 -0
  349. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/git.sh +0 -0
  350. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/https.sh +0 -0
  351. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/ui.sh +0 -0
  352. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-error.sh +0 -0
  353. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-sdk.sh +0 -0
  354. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/ui-sdk.sh +0 -0
  355. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.mcp-bash/vendor.json +0 -0
  356. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/mcp-commands.json +0 -0
  357. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/prompts.json +0 -0
  358. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/resource-templates.json +0 -0
  359. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/resources.json +0 -0
  360. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/.registry/ui-resources.json +0 -0
  361. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/Makefile +0 -0
  362. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/README.md +0 -0
  363. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/completions/entity-name.sh +0 -0
  364. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/completions/list-name.sh +0 -0
  365. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/completions/status-value.sh +0 -0
  366. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/docs/DEBUGGING.md +0 -0
  367. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/icon.svg +0 -0
  368. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/cache.sh +0 -0
  369. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/cli-detect.sh +0 -0
  370. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/cli-gateway.sh +0 -0
  371. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/common.sh +0 -0
  372. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/entity-types.sh +0 -0
  373. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/lib/field-resolution.sh +0 -0
  374. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/mcp-bash.lock +0 -0
  375. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/mcp-publisher.lock +0 -0
  376. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/mcpb.conf +0 -0
  377. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.completion.sh +0 -0
  378. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.meta.json +0 -0
  379. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.txt +0 -0
  380. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.meta.json +0 -0
  381. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.txt +0 -0
  382. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.meta.json +0 -0
  383. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.txt +0 -0
  384. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +0 -0
  385. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +0 -0
  386. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.meta.json +0 -0
  387. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.txt +0 -0
  388. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.completion.sh +0 -0
  389. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.meta.json +0 -0
  390. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.txt +0 -0
  391. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +0 -0
  392. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.txt +0 -0
  393. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.meta.json +0 -0
  394. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.txt +0 -0
  395. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/providers/xaffinity.sh +0 -0
  396. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.meta.json +0 -0
  397. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.meta.json +0 -0
  398. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.sh +0 -0
  399. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.json +0 -0
  400. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.meta.json +0 -0
  401. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/me/me.meta.json +0 -0
  402. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/me/me.sh +0 -0
  403. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.meta.json +0 -0
  404. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.sh +0 -0
  405. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.meta.json +0 -0
  406. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.sh +0 -0
  407. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.meta.json +0 -0
  408. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.sh +0 -0
  409. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.meta.json +0 -0
  410. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.sh +0 -0
  411. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.meta.json +0 -0
  412. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.sh +0 -0
  413. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-field-catalogs.completion.sh +0 -0
  414. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-saved-views.completion.sh +0 -0
  415. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-workflow-config.completion.sh +0 -0
  416. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.d/env.sh +0 -0
  417. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.d/health-checks.sh +0 -0
  418. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.d/policy.sh +0 -0
  419. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/server.json +0 -0
  420. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/test/README.md +0 -0
  421. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/test/run.sh +0 -0
  422. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/test/test_env_update_check.sh +0 -0
  423. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/test-progress.sh +0 -0
  424. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.meta.json +0 -0
  425. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.sh +0 -0
  426. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.sh +0 -0
  427. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.meta.json +0 -0
  428. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.sh +0 -0
  429. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.meta.json +0 -0
  430. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.sh +0 -0
  431. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.meta.json +0 -0
  432. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.sh +0 -0
  433. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/query/tool.sh +0 -0
  434. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.meta.json +0 -0
  435. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.sh +0 -0
  436. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/user-config.json +0 -0
  437. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp-env.sh +0 -0
  438. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp.sh +0 -0
  439. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/mkdocs.yml +0 -0
  440. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/plugin.json +0 -0
  441. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +0 -0
  442. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/references/services.md +0 -0
  443. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/guard-env-read.sh +0 -0
  444. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/hooks.json +0 -0
  445. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/files-and-writes.md +0 -0
  446. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/history-and-activity.md +0 -0
  447. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/interactions.md +0 -0
  448. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/query/test_cursor.py +0 -0
  449. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_company_create_dedup.py +0 -0
  450. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_company_ls_filter_rejection.py +0 -0
  451. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_formatters.py +0 -0
  452. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_output_formats_integration.py +0 -0
  453. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_person_create_dedup.py +0 -0
  454. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_person_ls_filter_rejection.py +0 -0
  455. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_filter_rejection.py +0 -0
  456. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_list_entry_relationships.py +0 -0
  457. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_list_export_parity.py +0 -0
  458. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_output_flattening.py +0 -0
  459. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_output_truncation.py +0 -0
  460. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cli/test_query_unreplied.py +0 -0
  461. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/conftest.py +0 -0
  462. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/.cowork-redact.json +0 -0
  463. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/README.md +0 -0
  464. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/README.txt +0 -0
  465. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/xaffinity-test-key +0 -0
  466. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-nokey/README.txt +0 -0
  467. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/image/Dockerfile +0 -0
  468. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/build_fixtures.py +0 -0
  469. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/fixtures.json +0 -0
  470. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/server.py +0 -0
  471. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/image/xaffinity-wrapper.sh +0 -0
  472. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/privacy-allow.txt +0 -0
  473. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/record.sh +0 -0
  474. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/scenarios/company-lists-status.yaml +0 -0
  475. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/scenarios/hook-blocks-without-key.yaml +0 -0
  476. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/scenarios/no-key-skill-path.yaml +0 -0
  477. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/scenarios/status-history.yaml +0 -0
  478. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/sessions/no-key.yaml +0 -0
  479. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/cowork/sessions/with-key.yaml +0 -0
  480. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/field_write_mocks.py +0 -0
  481. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/openapi/mini_openapi.json +0 -0
  482. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/field_value_updated.json +0 -0
  483. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/list_entry_created.json +0 -0
  484. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_created.json +0 -0
  485. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_merged.json +0 -0
  486. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/person_created.json +0 -0
  487. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/unknown_event.json +0 -0
  488. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/README.md +0 -0
  489. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/conftest.py +0 -0
  490. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/setup_query_parity_data.py +0 -0
  491. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/test_cli_writes.py +0 -0
  492. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/test_query_parity_integration.py +0 -0
  493. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/test_sdk_reads.py +0 -0
  494. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes.py +0 -0
  495. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes_runner.py +0 -0
  496. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/mcp/__init__.py +0 -0
  497. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/mcp/test_query_cursor.py +0 -0
  498. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/skill-evals/xaffinity-cli-usage-evals/evals.json +0 -0
  499. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/spec_guard.py +0 -0
  500. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
  501. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_api_coverage.py +0 -0
  502. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_api_key_file_formats.py +0 -0
  503. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_api_key_resolution.py +0 -0
  504. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_api_version.py +0 -0
  505. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_api_version_per_operation.py +0 -0
  506. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_async_file_download_streaming.py +0 -0
  507. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_batch_get.py +0 -0
  508. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_api_version.py +0 -0
  509. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_column_limiting.py +0 -0
  510. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_command_context.py +0 -0
  511. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_commands_must_fix.py +0 -0
  512. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_company_cmds_coverage.py +0 -0
  513. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_company_get.py +0 -0
  514. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_config_cmds.py +0 -0
  515. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_context_coverage.py +0 -0
  516. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_csv_export.py +0 -0
  517. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_date_params.py +0 -0
  518. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_date_utils.py +0 -0
  519. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_datetime_formatting.py +0 -0
  520. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_datetime_header_offsets.py +0 -0
  521. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_domain_linkification.py +0 -0
  522. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_dotenv_resolution.py +0 -0
  523. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_dropdown_field_writes.py +0 -0
  524. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_enriched_field_writes.py +0 -0
  525. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entity_field_writes.py +0 -0
  526. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entity_files_dump.py +0 -0
  527. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entry_field.py +0 -0
  528. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_batch_writes.py +0 -0
  529. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_multi_value_limits.py +0 -0
  530. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_error_hints.py +0 -0
  531. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_error_rendering.py +0 -0
  532. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_history.py +0 -0
  533. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_history_bulk.py +0 -0
  534. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_history_deleted_options.py +0 -0
  535. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_options_and_transcripts.py +0 -0
  536. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_utils.py +0 -0
  537. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_coverage.py +0 -0
  538. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_set_phase.py +0 -0
  539. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_field_value_humanization.py +0 -0
  540. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_file_url.py +0 -0
  541. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_files_ls.py +0 -0
  542. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_files_read.py +0 -0
  543. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_get_interaction_dates.py +0 -0
  544. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_help_json.py +0 -0
  545. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_interaction_date_chunking.py +0 -0
  546. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_interaction_utils.py +0 -0
  547. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_json_safety.py +0 -0
  548. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_cmds_coverage.py +0 -0
  549. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_expand_interactions.py +0 -0
  550. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_export_entity_scope.py +0 -0
  551. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_export_field_refresh.py +0 -0
  552. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_export_filter_safety.py +0 -0
  553. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_list_export_truncation_meta.py +0 -0
  554. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_missing_coverage.py +0 -0
  555. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_multi_value_truncation_warnings.py +0 -0
  556. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_no_network_commands.py +0 -0
  557. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_notes_writes.py +0 -0
  558. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds.py +0 -0
  559. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds_coverage.py +0 -0
  560. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_org.py +0 -0
  561. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_page_size_validation.py +0 -0
  562. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_pager_logic.py +0 -0
  563. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_person_cmds_coverage.py +0 -0
  564. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_person_get.py +0 -0
  565. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_plugin_manifest.py +0 -0
  566. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_pre_xaffinity_hook.py +0 -0
  567. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_progress_manager.py +0 -0
  568. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_aggregates.py +0 -0
  569. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd.py +0 -0
  570. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd_coverage.py +0 -0
  571. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_dates.py +0 -0
  572. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_expand_interactions.py +0 -0
  573. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_filters.py +0 -0
  574. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_integration.py +0 -0
  575. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_must_fix.py +0 -0
  576. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_parser.py +0 -0
  577. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_planner.py +0 -0
  578. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_review_fixes.py +0 -0
  579. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_safety.py +0 -0
  580. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_query_schema.py +0 -0
  581. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_rendering.py +0 -0
  582. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_throttle.py +0 -0
  583. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_reminders.py +0 -0
  584. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_render_coverage.py +0 -0
  585. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_repeated_filter.py +0 -0
  586. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_resolve_coverage.py +0 -0
  587. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_resolve_url_parsing.py +0 -0
  588. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_result_summary.py +0 -0
  589. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_safe_field_writes.py +0 -0
  590. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_search.py +0 -0
  591. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_serialization.py +0 -0
  592. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_session_cache.py +0 -0
  593. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_session_setup_hook.py +0 -0
  594. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_set_phase_atomicity.py +0 -0
  595. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_types.py +0 -0
  596. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_unreplied.py +0 -0
  597. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_update_check.py +0 -0
  598. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_v1_only_cmds.py +0 -0
  599. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_v1_parsing.py +0 -0
  600. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_webhooks.py +0 -0
  601. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_cli_write_ops.py +0 -0
  602. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_client.py +0 -0
  603. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_companies_create_dedup.py +0 -0
  604. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_companies_filter_rejection.py +0 -0
  605. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_duplicates_connections.py +0 -0
  606. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_env_helpers.py +0 -0
  607. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_exceptions_coverage.py +0 -0
  608. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_field_resolver.py +0 -0
  609. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_field_service_caching.py +0 -0
  610. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_field_types_c4.py +0 -0
  611. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_field_value_type.py +0 -0
  612. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_field_values_get_value.py +0 -0
  613. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_file_batch_get.py +0 -0
  614. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_file_download_streaming.py +0 -0
  615. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_file_list_batch.py +0 -0
  616. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_file_upload_helpers_and_validation.py +0 -0
  617. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_files_upload_returning_files.py +0 -0
  618. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_files_v2.py +0 -0
  619. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_filters.py +0 -0
  620. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_generate_mcp_command_registry.py +0 -0
  621. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_get_fields_filter_includes.py +0 -0
  622. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_get_fields_pagination.py +0 -0
  623. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_get_first.py +0 -0
  624. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_hidden_field_values.py +0 -0
  625. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_hooks.py +0 -0
  626. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_http_client_additional_coverage.py +0 -0
  627. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_http_client_remaining_coverage.py +0 -0
  628. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_inbound_webhooks.py +0 -0
  629. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_integration_smoke.py +0 -0
  630. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_interaction_date_validation.py +0 -0
  631. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_interactions_and_files_regressions.py +0 -0
  632. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_isodatetime.py +0 -0
  633. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_list_entry_membership_and_opportunities.py +0 -0
  634. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_list_term.py +0 -0
  635. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_lists_v2_writes.py +0 -0
  636. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_bundle_env_and_completions.py +0 -0
  637. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_cli_version_check.py +0 -0
  638. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_entity_dossier.py +0 -0
  639. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_gateway_limits.py +0 -0
  640. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_history_bulk_gateway.py +0 -0
  641. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_limits.py +0 -0
  642. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_must_fix.py +0 -0
  643. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_query_cli_error.py +0 -0
  644. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_read_truncation.py +0 -0
  645. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_mcp_resource_scripts.py +0 -0
  646. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_models.py +0 -0
  647. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_models_v2_2026_fields.py +0 -0
  648. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_multi_value_limits.py +0 -0
  649. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_new_features.py +0 -0
  650. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_notes_v2.py +0 -0
  651. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_notes_v2_writes.py +0 -0
  652. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_opportunities_filter_rejection.py +0 -0
  653. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_org_reads.py +0 -0
  654. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_pagination_iterators.py +0 -0
  655. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_persons_create_dedup.py +0 -0
  656. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_persons_filter_rejection.py +0 -0
  657. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_public_api.py +0 -0
  658. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_rate_limit_v2.py +0 -0
  659. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_raw_pipeline_hook_events.py +0 -0
  660. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_readonly_factory.py +0 -0
  661. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_reminder_list_batch.py +0 -0
  662. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_reminders_v2.py +0 -0
  663. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_requirements_additional.py +0 -0
  664. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_review_fixes_sdk_cli.py +0 -0
  665. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_sdk_interaction_dates.py +0 -0
  666. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_sdk_must_fix.py +0 -0
  667. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_search.py +0 -0
  668. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_search_v2.py +0 -0
  669. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_service_get_parameter_combinations.py +0 -0
  670. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_batch_get_interaction_dates.py +0 -0
  671. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_companies_coverage_gaps.py +0 -0
  672. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_dropdown_options.py +0 -0
  673. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_entity_field_updates.py +0 -0
  674. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_entity_list_entries.py +0 -0
  675. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_field_value_changes.py +0 -0
  676. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_list_entries_filter_paths.py +0 -0
  677. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_lists_additional_coverage.py +0 -0
  678. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_lists_coverage_gaps.py +0 -0
  679. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_opportunities_additional_coverage.py +0 -0
  680. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_opportunities_coverage_gaps.py +0 -0
  681. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
  682. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_pages_cursor_guard.py +0 -0
  683. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_persons_companies_additional_coverage.py +0 -0
  684. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_rate_limits_coverage_gaps.py +0 -0
  685. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_v1_only_async.py +0 -0
  686. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_services_v1_only_coverage_gaps.py +0 -0
  687. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_single_field_v2.py +0 -0
  688. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_small_modules_coverage.py +0 -0
  689. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_spec_guard.py +0 -0
  690. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_teams_users_feedback.py +0 -0
  691. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_transport_and_readonly_mode.py +0 -0
  692. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_v1_association_parsing.py +0 -0
  693. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_v1_only_services_additional_coverage.py +0 -0
  694. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_v1_only_services_more_coverage.py +0 -0
  695. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_v2_request_bodies.py +0 -0
  696. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_validate_openapi_tool.py +0 -0
  697. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/test_webhooks_v2.py +0 -0
  698. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/unit/__init__.py +0 -0
  699. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tests/unit/test_exceptions.py +0 -0
  700. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/__init__.py +0 -0
  701. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/api_coverage.json +0 -0
  702. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/api_coverage.py +0 -0
  703. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/api_coverage_v1_snapshot.json +0 -0
  704. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/check_cli_patterns.py +0 -0
  705. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/generate_mcp_command_registry.py +0 -0
  706. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/generate_release_notes.py +0 -0
  707. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/generate_requirements_mapping.py +0 -0
  708. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2024-01-01.json +0 -0
  709. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-07-15.json +0 -0
  710. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-09-17.json +0 -0
  711. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/sync_mcp_bundle_env.py +0 -0
  712. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/sync_mcp_registry.py +0 -0
  713. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/sync_mcp_version.py +0 -0
  714. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/validate_mcp_registry_metadata.py +0 -0
  715. {affinity_sdk-2.0.7 → affinity_sdk-2.0.8}/tools/validate_openapi_models.py +0 -0
@@ -5,6 +5,41 @@ 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
+
8
43
  ## [2.0.7] - 2026-11-03
9
44
 
10
45
  **Exception to semantic versioning** (as 2.0.2–2.0.6): two fixes change which rows a filter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: affinity-sdk
3
- Version: 2.0.7
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
@@ -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,
@@ -1149,6 +1150,33 @@ def list_export(
1149
1150
  api_called=True,
1150
1151
  )
1151
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
+
1152
1180
  # Build expand field data structures from parsed_expand_fields
1153
1181
  # - expand_field_ids: list of field IDs for API calls
1154
1182
  # - field_id_to_display: dict mapping field ID (str) -> display name (original spec)
@@ -1338,7 +1366,8 @@ def list_export(
1338
1366
  state=csv_iter_state,
1339
1367
  cache=cache,
1340
1368
  filter_progress_callback=filter_callback,
1341
- search=list_search.body if list_search else None,
1369
+ search=search_body,
1370
+ opened_page=opened_page,
1342
1371
  filter_field_ids=filter_field_ids,
1343
1372
  ):
1344
1373
  next_cursor = page_next_cursor
@@ -1664,7 +1693,6 @@ def list_export(
1664
1693
  # only reach the JSON envelope, which CSV never builds.
1665
1694
  for msg in [
1666
1695
  *warnings,
1667
- *csv_iter_state.get("warnings", []),
1668
1696
  *truncation_warnings(
1669
1697
  csv_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
1670
1698
  ),
@@ -1776,7 +1804,8 @@ def list_export(
1776
1804
  state=table_iter_state,
1777
1805
  cache=cache,
1778
1806
  filter_progress_callback=json_filter_callback,
1779
- search=list_search.body if list_search else None,
1807
+ search=search_body,
1808
+ opened_page=opened_page,
1780
1809
  filter_field_ids=filter_field_ids,
1781
1810
  ):
1782
1811
  next_cursor = page_next_cursor
@@ -1919,9 +1948,6 @@ def list_export(
1919
1948
  warnings.append("Results limited by --max-results. Use --all to fetch all results.")
1920
1949
  from ..field_utils import truncation_warnings
1921
1950
 
1922
- warnings.extend(table_iter_state.get("warnings", []))
1923
- if server_filter is not None and table_iter_state.get("searchFallback"):
1924
- server_filter["fallback"] = table_iter_state["searchFallback"]
1925
1951
  warnings.extend(
1926
1952
  truncation_warnings(
1927
1953
  table_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
@@ -2115,6 +2141,7 @@ def _iterate_list_entries(
2115
2141
  cache: Any = None,
2116
2142
  filter_progress_callback: Callable[[FilterStats], None] | None = None,
2117
2143
  search: dict[str, Any] | None = None,
2144
+ opened_page: PaginatedResponse[ListEntryWithEntity] | None = None,
2118
2145
  filter_field_ids: list[str] | None = None,
2119
2146
  ) -> Any:
2120
2147
  """
@@ -2196,38 +2223,27 @@ def _iterate_list_entries(
2196
2223
  else None
2197
2224
  )
2198
2225
  if decoded is not None or (search is not None and filter_expr):
2199
- try:
2200
- if decoded is not None:
2201
- assert decoded.body is not None
2202
- body, local_filter = decoded.body, decoded.filter
2203
- first = entries.find_body(body, cursor=decoded.url)
2204
- else:
2205
- assert search is not None and filter_expr
2206
- body, local_filter = search, parse_filter(filter_expr)
2207
- first = entries.find_body(body, field_ids=fetch_ids, limit=page_size)
2208
- except (AuthorizationError, NotFoundError, SDKValidationError) as e:
2209
- if decoded is not None:
2210
- raise
2211
- if state is not None:
2212
- state.setdefault("warnings", []).append(
2213
- f"Affinity's search refused the filter, filtering locally: {e}"
2214
- )
2215
- 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)
2216
2230
  else:
2217
- yield from _search_rows(
2218
- entries,
2219
- first,
2220
- body=body,
2221
- local_filter=local_filter,
2222
- selected_field_ids=selected_field_ids,
2223
- field_by_id=field_by_id,
2224
- key_mode=key_mode,
2225
- max_results=max_results,
2226
- all_pages=all_pages,
2227
- state=state,
2228
- filter_progress_callback=filter_progress_callback,
2229
- )
2230
- 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
2231
2247
 
2232
2248
  pages = (
2233
2249
  entries.pages(cursor=cursor)
@@ -2300,17 +2316,39 @@ def _filter_names_list_fields(filter_expr: str) -> bool:
2300
2316
  return False
2301
2317
 
2302
2318
 
2303
- def _filter_scope_error(filter_expr: str, local: list[str]) -> CLIError:
2304
- return CLIError(
2305
- "Part of this --filter runs locally on fetched pages, so without a scope flag the "
2306
- "export would silently return only first-page matches. Add --all to scan everything, "
2307
- "--max-results N to cap, or --first-page-only to opt in.",
2308
- exit_code=2,
2309
- error_type="usage_error",
2310
- hint="details.local names the conditions Affinity's search can't apply; --saved-view "
2311
- "filters large lists on Affinity's side.",
2312
- 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."
2313
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)
2314
2352
 
2315
2353
 
2316
2354
  def _search_rows(
@@ -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,8 +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 that also match their id) plus the record's own
98
- attributes."""
97
+ text, persons and companies as names; a number in a filter matches their id) plus the
98
+ record's own attributes."""
99
99
  result: dict[str, Any] = {}
100
100
  by_id: dict[str, Any] = {}
101
101
  for item in getattr(entity, "fields_raw", None) or []:
@@ -271,7 +271,7 @@ def _normalize_list_entry_fields(
271
271
  extracted.append(item)
272
272
  normalized_fields[field_name] = extracted
273
273
  # Handle person reference: {"firstName": "Jane", "lastName": "Doe"}
274
- # (names carry the record id: a filter on the id matches too)
274
+ # (names carry the record id: a number in a filter matches the id only)
275
275
  elif isinstance(data, dict) and ("firstName" in data or "lastName" in data):
276
276
  normalized_fields[field_name] = entity_name(
277
277
  _extract_person_display_name(data), data.get("id")
@@ -1887,7 +1887,7 @@ class QueryExecutor:
1887
1887
  would mean reading Affinity's whole directory."""
1888
1888
  from affinity.services._search import SEARCH_INCLUDES
1889
1889
 
1890
- from .pushdown import fields_index, split_where
1890
+ from .pushdown import ENTITY_VERIFIED, fields_index, split_where
1891
1891
 
1892
1892
  where = ctx.query.where
1893
1893
  if entity not in ("companies", "persons"):
@@ -1915,7 +1915,13 @@ class QueryExecutor:
1915
1915
  if meta is not None:
1916
1916
  field_ids.add(str(meta.id))
1917
1917
  self._search_field_ids = sorted(field_ids)
1918
- split = split_where(where, fields, lambda m: options.get(str(m.id), []), enriched="as-is")
1918
+ split = split_where(
1919
+ where,
1920
+ fields,
1921
+ lambda m: options.get(str(m.id), []),
1922
+ verified=ENTITY_VERIFIED,
1923
+ enriched="as-is",
1924
+ )
1919
1925
  if split.errors:
1920
1926
  raise QueryValidationError("; ".join(split.errors), field="where")
1921
1927
  if names and not split.server_side:
@@ -0,0 +1,25 @@
1
+ """Server-side filter split (moved to :mod:`affinity._filtering.pushdown`; re-exported)."""
2
+
3
+ from ..._filtering.pushdown import (
4
+ ALL_MAPPINGS,
5
+ ENRICHED,
6
+ ENTITY_VERIFIED,
7
+ ID_MAX,
8
+ REFERENCE_MAPPINGS,
9
+ VERIFIED,
10
+ Pushdown,
11
+ fields_index,
12
+ split_where,
13
+ )
14
+
15
+ __all__ = [
16
+ "ALL_MAPPINGS",
17
+ "ENRICHED",
18
+ "ENTITY_VERIFIED",
19
+ "ID_MAX",
20
+ "REFERENCE_MAPPINGS",
21
+ "VERIFIED",
22
+ "Pushdown",
23
+ "fields_index",
24
+ "split_where",
25
+ ]
@@ -18,7 +18,8 @@ from ._filtering.dates import as_utc, parse_date_value, parse_iso_datetime
18
18
 
19
19
  class EntityName(str):
20
20
  """A person's or company's name (or another record reference's) that also carries the
21
- record's id, so a filter can match either: ``Owner = "Jane Doe"`` or ``Owner = 123``.
21
+ record's id: ``Owner = "Jane Doe"`` matches the name, ``Owner = 123`` the id (a number is
22
+ the id only; it never matches a name made of digits).
22
23
 
23
24
  It is a ``str`` everywhere else (output, sorting, text operators)."""
24
25
 
@@ -49,7 +50,8 @@ def entity_name(value: Any, entity_id: Any) -> Any:
49
50
 
50
51
 
51
52
  def _as_entity_id(value: Any) -> int | None:
52
- """A filter value read as a record id: an int, or a string of ASCII digits."""
53
+ """A filter value read as a record id: an int, or a string of 1-20 ASCII digits (surrounding
54
+ spaces ignored)."""
53
55
  if isinstance(value, bool):
54
56
  return None
55
57
  if isinstance(value, int):
@@ -68,7 +70,7 @@ def normalize_value(value: Any) -> Any:
68
70
  - Dropdowns become their text: {"text": "Active"} -> "Active"
69
71
  - Persons become their name: {"firstName": "Jane", "lastName": "Doe"} -> "Jane Doe"
70
72
  - Companies become their name: {"name": "Acme", "domain": ...} -> "Acme"
71
- (as :class:`EntityName`, carrying the record id, so a number matches the id)
73
+ (as :class:`EntityName`, carrying the record id, so a number matches the id only)
72
74
  - Multi-value arrays become lists of those: [{"text": "A"}, {"text": "B"}] -> ["A", "B"]
73
75
  - Scalars pass through unchanged
74
76
 
@@ -226,19 +228,23 @@ def _eq(a: Any, b: Any) -> bool:
226
228
 
227
229
  def _scalar_eq(a: Any, b: Any) -> bool:
228
230
  """Scalar equality as ``eq`` uses it, and ``in`` / ``has_any`` / ``has_all`` per element:
229
- direct, then an :class:`EntityName` against its id, then ``"true"``/``"false"`` against a
230
- bool, then by string (``5`` matches ``"5"``). ``a`` is the field value."""
231
+ an :class:`EntityName` against an id-shaped value is an id comparison only; otherwise
232
+ direct, then ``"true"``/``"false"`` against a bool, then by string (``5`` matches ``"5"``).
233
+ ``a`` is the field value."""
231
234
  if a is None or b is None:
232
235
  return a is b
233
236
 
237
+ # A record reference (person, company, list...) against a number or digit string is its
238
+ # id, never a name made of digits (Owner = 123 does not match a person named "123")
239
+ if isinstance(a, EntityName) and a.entity_id is not None:
240
+ record_id = _as_entity_id(b)
241
+ if record_id is not None:
242
+ return record_id == a.entity_id
243
+
234
244
  # Try direct comparison first
235
245
  if a == b:
236
246
  return True
237
247
 
238
- # A person or company also matches its id (Owner = 123)
239
- if isinstance(a, EntityName) and a.entity_id is not None and _as_entity_id(b) == a.entity_id:
240
- return True
241
-
242
248
  # Handle boolean coercion: filter string "true"/"false" should match Python bool
243
249
  # Filter parser outputs lowercase "true"/"false", Python str(True) is "True"
244
250
  if isinstance(a, bool) and isinstance(b, str):
@@ -278,7 +278,7 @@ Options:
278
278
  - `--csv`: output as CSV (to stdout)
279
279
  - `--csv-bom`: add UTF-8 BOM for Excel compatibility
280
280
 
281
- **Note:** `--filter` goes through Affinity's search: the conditions on person fields that Affinity can answer are applied on its side, and the whole filter (including attributes like `firstName` or `primaryEmail`) then runs on what comes back. A filter with only attribute conditions is refused; search names and emails with `--query`. When part of the filter runs locally, `--all` or `--max-results` is required. Filters on enriched fields warn that a few records may be missed. The next-page cursor of a filtered run starts with `xsearch2:` and `--cursor` alone resumes it. `--query` and `--filter` can't be combined. With `--json`, `meta.serverFilter` lists the conditions Affinity applied (`pushed`) and those checked locally (`local`); a `--cursor` resume doesn't report it.
281
+ **Note:** `--filter` goes through Affinity's search: the conditions on person fields that Affinity can answer are applied on its side, and the whole filter (including attributes like `firstName` or `primaryEmail`) then runs on what comes back. A filter with only attribute conditions is refused; search names and emails with `--query`. When part of the filter runs locally, `--all` or `--max-results` is required. Filters on enriched fields warn that a few records may be missed. Id conditions on person and company fields (`Mentor = 9`) are checked locally here, and a `starts_word` made only of digits needs another field condition (or use `--query`). The next-page cursor of a filtered run starts with `xsearch2:` and `--cursor` alone resumes it. `--query` and `--filter` can't be combined. With `--json`, `meta.serverFilter` lists the conditions Affinity applied (`pushed`) and those checked locally (`local`); a `--cursor` resume doesn't report it.
282
282
 
283
283
  **Note:** `--query` can be combined with `--field` and `--field-type` to search with field data.
284
284
 
@@ -461,7 +461,7 @@ Options:
461
461
  - `--csv`: output as CSV (to stdout)
462
462
  - `--csv-bom`: add UTF-8 BOM for Excel compatibility
463
463
 
464
- **Note:** `--filter` goes through Affinity's search: the conditions on company fields that Affinity can answer are applied on its side, and the whole filter (including attributes like `name` or `domain`) then runs on what comes back. A filter with only attribute conditions (e.g. `name =~ "Acme"`) is refused, since it would mean reading Affinity's whole company directory; search names and domains with `--query`. When part of the filter runs locally, `--all` or `--max-results` is required. Filters on enriched fields warn that a few records may be missed. The next-page cursor of a filtered run starts with `xsearch2:` and `--cursor` alone resumes it. `--query` and `--filter` can't be combined. With `--json`, `meta.serverFilter` lists the conditions Affinity applied (`pushed`) and those checked locally (`local`); a `--cursor` resume doesn't report it.
464
+ **Note:** `--filter` goes through Affinity's search: the conditions on company fields that Affinity can answer are applied on its side, and the whole filter (including attributes like `name` or `domain`) then runs on what comes back. A filter with only attribute conditions (e.g. `name =~ "Acme"`) is refused, since it would mean reading Affinity's whole company directory; search names and domains with `--query`. When part of the filter runs locally, `--all` or `--max-results` is required. Filters on enriched fields warn that a few records may be missed. Id conditions on person and company fields (`Mentor = 9`) are checked locally here, and a `starts_word` made only of digits needs another field condition (or use `--query`). The next-page cursor of a filtered run starts with `xsearch2:` and `--cursor` alone resumes it. `--query` and `--filter` can't be combined. With `--json`, `meta.serverFilter` lists the conditions Affinity applied (`pushed`) and those checked locally (`local`); a `--cursor` resume doesn't report it.
465
465
 
466
466
  **Note:** `--query` can be combined with `--field` and `--field-type` to search with field data.
467
467
 
@@ -849,7 +849,7 @@ Options:
849
849
  - `--unreplied-types <types>`: Comma-separated types to check: email, chat, all (default: email,chat)
850
850
  - `--unreplied-lookback-days <days>`: Lookback period for unreplied message detection (default: 30)
851
851
 
852
- **`--filter` and Affinity's search.** Conditions on list fields that Affinity's search can answer are applied on its side, so only matching entries are downloaded; the whole filter still runs locally on what comes back. When Affinity applies the whole filter, `--all`, `--max-results` and `--first-page-only` are not required (page one is the first page of matches). When part of the filter runs locally, one of them is required, otherwise the command exits with code 2 and the error's `details.local` names the conditions that stay local. The next-page cursor of a filtered export starts with `xsearch2:` and carries the search, so `--cursor` alone resumes it. If Affinity refuses the search (e.g. the API key lacks the "Export data from Lists" permission), the export reads the whole list and filters locally, with a warning. With `--json`, `meta.serverFilter` reports the split (in `--dry-run`, `data.serverFilter`): `pushed` (conditions Affinity's search applied), `local` (what runs only on your machine, with reasons) and, when the search was refused or turned off, `fallback` (why; the whole filter then ran locally). A `--cursor` resume doesn't report it. CSV and table output report the split as warnings on stderr. `XAFFINITY_QUERY_SERVER_FILTER=0` turns server filtering off for list entries (`query` on listEntries and `list export`); company and person filters always use it. `--saved-view` also filters on Affinity's side; for one known company or person use `--company-id` / `--person-id`. See [Filtering](../guides/filtering.md#filtering-on-affinitys-side) for which conditions Affinity applies.
852
+ **`--filter` and Affinity's search.** Conditions on list fields that Affinity's search can answer are applied on its side, so only matching entries are downloaded; the whole filter still runs locally on what comes back. When Affinity applies the whole filter, `--all`, `--max-results` and `--first-page-only` are not required (page one is the first page of matches). When part of the filter runs locally, one of them is required, otherwise the command exits with code 2 and the error's `details.local` names the conditions that stay local. The next-page cursor of a filtered export starts with `xsearch2:` and carries the search, so `--cursor` alone resumes it. If Affinity refuses the search (e.g. the API key lacks the "Export data from Lists" permission), the export reads the whole list and filters locally, with a warning, when `--all`, `--max-results` or `--first-page-only` is given; without one the command exits with code 2 before any output (`details.refused` carries the refusal). Id conditions on person and company fields (`Owner = 12345`, ids up to 2147483647) are applied on Affinity's side; names, `!=` and enriched fields of those types run locally, and a `starts_word` made only of digits runs locally too, so it needs a scope flag. With `--json`, `meta.serverFilter` reports the split (in `--dry-run`, `data.serverFilter`): `pushed` (conditions Affinity's search applied), `local` (what runs only on your machine, with reasons) and, when the search was refused or turned off, `fallback` (why; the whole filter then ran locally). A `--cursor` resume doesn't report it. CSV and table output report the split as warnings on stderr. `XAFFINITY_QUERY_SERVER_FILTER=0` turns server filtering off for list entries (`query` on listEntries and `list export`); company and person filters always use it. `--saved-view` also filters on Affinity's side; for one known company or person use `--company-id` / `--person-id`. See [Filtering](../guides/filtering.md#filtering-on-affinitys-side) for which conditions Affinity applies.
853
853
 
854
854
  **Truncation envelope.** JSON output includes a `meta` object with `truncated` (boolean) and, when `truncated=true`, a `truncationReason` string naming the cause (`firstPageOnly` here; `field history-bulk` uses `partialFailure`). Always check this before treating a response as complete.
855
855