affinity-sdk 2.0.2__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (699) hide show
  1. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/CHANGELOG.md +59 -0
  2. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/PKG-INFO +1 -1
  3. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/__init__.py +2 -0
  4. affinity_sdk-2.0.3/affinity/_filtering/__init__.py +5 -0
  5. {affinity_sdk-2.0.2/affinity/cli/query → affinity_sdk-2.0.3/affinity/_filtering}/dates.py +26 -12
  6. {affinity_sdk-2.0.2/affinity/cli/query → affinity_sdk-2.0.3/affinity/_filtering}/filter_text.py +4 -4
  7. {affinity_sdk-2.0.2/affinity/cli/query → affinity_sdk-2.0.3/affinity/_filtering}/pushdown.py +11 -5
  8. affinity_sdk-2.0.3/affinity/_filtering/search.py +305 -0
  9. affinity_sdk-2.0.3/affinity/_filtering/where.py +108 -0
  10. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/company_cmds.py +2 -2
  11. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/list_cmds.py +49 -18
  12. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/org_cmds.py +75 -1
  13. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/person_cmds.py +2 -2
  14. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/query_cmd.py +4 -3
  15. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/entity_search.py +18 -13
  16. affinity_sdk-2.0.3/affinity/cli/list_search.py +90 -0
  17. affinity_sdk-2.0.3/affinity/cli/query/dates.py +21 -0
  18. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/executor.py +137 -32
  19. affinity_sdk-2.0.3/affinity/cli/query/filter_text.py +5 -0
  20. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/filters.py +3 -2
  21. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/models.py +6 -93
  22. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/planner.py +35 -2
  23. affinity_sdk-2.0.3/affinity/cli/query/pushdown.py +12 -0
  24. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/compare.py +43 -0
  25. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/exceptions.py +9 -0
  26. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/org.py +9 -3
  27. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/lists.py +493 -349
  28. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/org.py +173 -2
  29. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/cli/commands.md +11 -0
  30. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/filtering.md +11 -6
  31. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/api-coverage.md +3 -1
  32. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/plugin.json +1 -1
  33. affinity_sdk-2.0.3/mcp/.mcp-bash/VERSION +1 -0
  34. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/core.sh +60 -7
  35. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/tools.sh +13 -3
  36. affinity_sdk-2.0.3/mcp/.mcp-bash/vendor.json +1 -0
  37. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/commands.generated.json +123 -5
  38. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/mcp-commands.json +10 -2
  39. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/CHANGELOG.md +19 -0
  40. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/COMPATIBILITY +7 -2
  41. affinity_sdk-2.0.3/mcp/VERSION +1 -0
  42. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/mcp-bash.lock +2 -2
  43. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.d/requirements.json +1 -1
  44. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.d/server.meta.json +1 -1
  45. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/query/tool.meta.json +1 -1
  46. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/affinity-sdk/.claude-plugin/plugin.json +1 -1
  47. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +7 -4
  48. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/pyproject.toml +1 -1
  49. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/cassettes/company-lists-status.cassette.json +86 -86
  50. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/cassettes/hook-blocks-without-key.cassette.json +63 -63
  51. affinity_sdk-2.0.3/tests/cowork/cassettes/no-key-skill-path.cassette.json +417 -0
  52. affinity_sdk-2.0.3/tests/cowork/cassettes/status-history.cassette.json +492 -0
  53. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entity_ls_server_filter.py +84 -1
  54. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_export_filter_safety.py +5 -3
  55. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_export_server_filter.py +16 -2
  56. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_org.py +32 -0
  57. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_server_filter.py +90 -0
  58. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_compare.py +35 -0
  59. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_filters.py +10 -0
  60. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_get_first.py +6 -0
  61. affinity_sdk-2.0.3/tests/test_list_entries_server_filter.py +270 -0
  62. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_teams_users_feedback.py +38 -0
  63. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/api_coverage.json +14 -0
  64. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/openapi_snapshots/2024-01-01.json +2 -2
  65. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/openapi_snapshots/2026-07-15.json +2 -2
  66. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/openapi_snapshots/2026-09-17.json +112 -2
  67. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/search_golden.py +45 -5
  68. affinity_sdk-2.0.2/affinity/cli/list_search.py +0 -92
  69. affinity_sdk-2.0.2/mcp/.mcp-bash/VERSION +0 -1
  70. affinity_sdk-2.0.2/mcp/.mcp-bash/vendor.json +0 -1
  71. affinity_sdk-2.0.2/mcp/VERSION +0 -1
  72. affinity_sdk-2.0.2/tests/cowork/cassettes/no-key-skill-path.cassette.json +0 -395
  73. affinity_sdk-2.0.2/tests/cowork/cassettes/status-history.cassette.json +0 -469
  74. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.claude-plugin/marketplace.json +0 -0
  75. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.cursor/rules/test-data-privacy.mdc +0 -0
  76. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.editorconfig +0 -0
  77. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.env.example +0 -0
  78. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.gitattributes +0 -0
  79. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/CODEOWNERS +0 -0
  80. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  81. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  82. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
  83. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/PULL_REQUEST_TEMPLATE/release.md +0 -0
  84. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/dependabot.yml +0 -0
  85. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/labels.yml +0 -0
  86. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/mcp-release-install-footer.md +0 -0
  87. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/pull_request_template.md +0 -0
  88. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/release-install-footer.md +0 -0
  89. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/ci.yml +0 -0
  90. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/cowork-replay.yml +0 -0
  91. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/docs.yml +0 -0
  92. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/labels.yml +0 -0
  93. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/linkcheck.yml +0 -0
  94. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/openapi-validation.yml +0 -0
  95. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/plugin-build.yml +0 -0
  96. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/plugin-release.yml +0 -0
  97. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/release-detect.yml +0 -0
  98. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/release.yml +0 -0
  99. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.github/workflows/version-check.yml +0 -0
  100. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.gitignore +0 -0
  101. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/.pre-commit-config.yaml +0 -0
  102. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/AGENTS.md +0 -0
  103. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/CODE_OF_CONDUCT.md +0 -0
  104. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/CONTRIBUTING.md +0 -0
  105. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/LICENSE +0 -0
  106. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/README.md +0 -0
  107. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/SECURITY.md +0 -0
  108. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/VERSIONING.md +0 -0
  109. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/_internal/__init__.py +0 -0
  110. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/_internal/keyfile.py +0 -0
  111. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/api_versions.py +0 -0
  112. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/__init__.py +0 -0
  113. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/__main__.py +0 -0
  114. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/_update_worker.py +0 -0
  115. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/click_compat.py +0 -0
  116. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/__init__.py +0 -0
  117. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_entity_field.py +0 -0
  118. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_entity_files_dump.py +0 -0
  119. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_entity_files_read.py +0 -0
  120. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_entity_files_upload.py +0 -0
  121. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_list_entry_fields.py +0 -0
  122. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_org_reads.py +0 -0
  123. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_search_common.py +0 -0
  124. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/_v1_parsing.py +0 -0
  125. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/completion_cmd.py +0 -0
  126. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/config_cmds.py +0 -0
  127. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/discovery_cmds.py +0 -0
  128. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/entry_cmds.py +0 -0
  129. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/field_cmds.py +0 -0
  130. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/file_cmds.py +0 -0
  131. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/file_url_cmd.py +0 -0
  132. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/interaction_cmds.py +0 -0
  133. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/note_cmds.py +0 -0
  134. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/opportunity_cmds.py +0 -0
  135. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/org_read_cmds.py +0 -0
  136. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/relationship_strength_cmds.py +0 -0
  137. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/reminder_cmds.py +0 -0
  138. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/resolve_url_cmd.py +0 -0
  139. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/session_cmds.py +0 -0
  140. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/task_cmds.py +0 -0
  141. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/transcript_cmds.py +0 -0
  142. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/version_cmd.py +0 -0
  143. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/webhook_cmds.py +0 -0
  144. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/commands/whoami_cmd.py +0 -0
  145. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/config.py +0 -0
  146. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/confirm.py +0 -0
  147. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/constants.py +0 -0
  148. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/context.py +0 -0
  149. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/csv_utils.py +0 -0
  150. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/date_utils.py +0 -0
  151. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/decorators.py +0 -0
  152. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/errors.py +0 -0
  153. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/field_utils.py +0 -0
  154. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/formatters.py +0 -0
  155. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/help_json.py +0 -0
  156. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/interaction_utils.py +0 -0
  157. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/logging.py +0 -0
  158. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/main.py +0 -0
  159. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/mcp_limits.py +0 -0
  160. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/options.py +0 -0
  161. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/paths.py +0 -0
  162. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/progress.py +0 -0
  163. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/__init__.py +0 -0
  164. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/aggregates.py +0 -0
  165. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/cursor.py +0 -0
  166. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/exceptions.py +0 -0
  167. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/output.py +0 -0
  168. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/parser.py +0 -0
  169. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/progress.py +0 -0
  170. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/query/schema.py +0 -0
  171. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/render.py +0 -0
  172. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/resolve.py +0 -0
  173. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/resolvers.py +0 -0
  174. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/results.py +0 -0
  175. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/runner.py +0 -0
  176. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/serialization.py +0 -0
  177. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/session_cache.py +0 -0
  178. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/types.py +0 -0
  179. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/cli/update_check.py +0 -0
  180. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/client.py +0 -0
  181. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/clients/__init__.py +0 -0
  182. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/clients/http.py +0 -0
  183. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/clients/pipeline.py +0 -0
  184. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/criteria.py +0 -0
  185. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/downloads.py +0 -0
  186. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/field_resolve_utils.py +0 -0
  187. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/field_resolver.py +0 -0
  188. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/filters.py +0 -0
  189. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/hooks.py +0 -0
  190. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/inbound_webhooks.py +0 -0
  191. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/__init__.py +0 -0
  192. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/discovery.py +0 -0
  193. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/entities.py +0 -0
  194. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/interactions_v2.py +0 -0
  195. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/pagination.py +0 -0
  196. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/rate_limit_snapshot.py +0 -0
  197. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/relationships_v2.py +0 -0
  198. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/search.py +0 -0
  199. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/secondary.py +0 -0
  200. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/transcripts.py +0 -0
  201. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/models/types.py +0 -0
  202. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/policies.py +0 -0
  203. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/progress.py +0 -0
  204. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/py.typed +0 -0
  205. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/__init__.py +0 -0
  206. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_discovery.py +0 -0
  207. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_dropdown_options.py +0 -0
  208. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_field_listing.py +0 -0
  209. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_field_updates.py +0 -0
  210. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_note_html.py +0 -0
  211. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_org_reads.py +0 -0
  212. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_search.py +0 -0
  213. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_single_field.py +0 -0
  214. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/_v2_filters.py +0 -0
  215. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/companies.py +0 -0
  216. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/opportunities.py +0 -0
  217. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/persons.py +0 -0
  218. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/rate_limits.py +0 -0
  219. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/reminders.py +0 -0
  220. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/search.py +0 -0
  221. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/tasks.py +0 -0
  222. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/transcripts.py +0 -0
  223. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/v1_only.py +0 -0
  224. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/services/webhooks.py +0 -0
  225. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/affinity/types.py +0 -0
  226. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/codecov.yml +0 -0
  227. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/cli-development-guide.md +0 -0
  228. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/ai-integrations/index.md +0 -0
  229. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/changelog.md +0 -0
  230. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/cli/index.md +0 -0
  231. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/cli/scripting.md +0 -0
  232. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/cli-reference.md +0 -0
  233. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/examples.md +0 -0
  234. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/getting-started.md +0 -0
  235. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/glossary.md +0 -0
  236. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/affinity-official-mcp-comparison.md +0 -0
  237. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/api-versions-and-routing.md +0 -0
  238. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/api-versions.md +0 -0
  239. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/authentication.md +0 -0
  240. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/claude-code-plugins.md +0 -0
  241. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/configuration.md +0 -0
  242. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/csv-export.md +0 -0
  243. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/datetime-handling.md +0 -0
  244. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/debugging-hooks.md +0 -0
  245. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/errors-and-retries.md +0 -0
  246. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/field-types-and-values.md +0 -0
  247. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/field-values.md +0 -0
  248. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/ids-and-types.md +0 -0
  249. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/migrating-to-2.md +0 -0
  250. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/models.md +0 -0
  251. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/opportunity-associations.md +0 -0
  252. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/pagination.md +0 -0
  253. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/performance.md +0 -0
  254. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/query-command.md +0 -0
  255. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/rate-limits.md +0 -0
  256. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/sync-vs-async.md +0 -0
  257. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/guides/webhooks.md +0 -0
  258. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/index.md +0 -0
  259. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/mcp/index.md +0 -0
  260. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/client.md +0 -0
  261. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/exceptions.md +0 -0
  262. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/filters.md +0 -0
  263. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/models.md +0 -0
  264. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/query-language.md +0 -0
  265. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/companies.md +0 -0
  266. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/lists.md +0 -0
  267. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/opportunities.md +0 -0
  268. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/persons.md +0 -0
  269. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/reminders.md +0 -0
  270. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/tasks.md +0 -0
  271. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/teams-users.md +0 -0
  272. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/auth.md +0 -0
  273. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/field-values.md +0 -0
  274. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/fields.md +0 -0
  275. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/files.md +0 -0
  276. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/interactions.md +0 -0
  277. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/notes.md +0 -0
  278. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/v1/relationships.md +0 -0
  279. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/services/webhooks.md +0 -0
  280. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/reference/types.md +0 -0
  281. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/docs/public/troubleshooting.md +0 -0
  282. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/advanced_usage.py +0 -0
  283. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/async_lifecycle.py +0 -0
  284. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/basic_usage.py +0 -0
  285. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/filter_builder.py +0 -0
  286. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/hooks_debugging.py +0 -0
  287. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/list_management.py +0 -0
  288. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/resolve_helpers.py +0 -0
  289. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/examples/task_polling.py +0 -0
  290. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/.gitignore +0 -0
  291. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +0 -0
  292. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/pipeline-history/SKILL.md +0 -0
  293. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/query-language/SKILL.md +0 -0
  294. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/query-language/references/filter-operators.md +0 -0
  295. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/query-language/references/include-expand.md +0 -0
  296. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/query-language/references/output-formats.md +0 -0
  297. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/skills/query-language/references/quantifiers.md +0 -0
  298. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.claude-plugin/xaffinity-mcp.sh +0 -0
  299. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.gitignore +0 -0
  300. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/bin/mcp-bash +0 -0
  301. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/completion.sh +0 -0
  302. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/lifecycle.sh +0 -0
  303. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/logging.sh +0 -0
  304. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/ping.sh +0 -0
  305. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/prompts.sh +0 -0
  306. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/resources.sh +0 -0
  307. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/roots.sh +0 -0
  308. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/handlers/tools.sh +0 -0
  309. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/auth.sh +0 -0
  310. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/capabilities.sh +0 -0
  311. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/cli/common.sh +0 -0
  312. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/cli/health.sh +0 -0
  313. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/completion.sh +0 -0
  314. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/elicitation.sh +0 -0
  315. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/file_read.sh +0 -0
  316. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/handler_helpers.sh +0 -0
  317. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/hash.sh +0 -0
  318. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/ids.sh +0 -0
  319. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/io.sh +0 -0
  320. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/json.sh +0 -0
  321. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/lock.sh +0 -0
  322. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/logging.sh +0 -0
  323. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/meta_env.sh +0 -0
  324. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/paginate.sh +0 -0
  325. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/path.sh +0 -0
  326. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/policy.sh +0 -0
  327. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/progress-passthrough.sh +0 -0
  328. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/progress.sh +0 -0
  329. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/prompts.sh +0 -0
  330. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/registry.sh +0 -0
  331. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/require.sh +0 -0
  332. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/resource_content.sh +0 -0
  333. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/resource_match.sh +0 -0
  334. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/resource_providers.sh +0 -0
  335. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/resources.sh +0 -0
  336. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/roots.sh +0 -0
  337. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/rpc.sh +0 -0
  338. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/runtime.sh +0 -0
  339. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/spec.sh +0 -0
  340. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/timeout.sh +0 -0
  341. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/tools_policy.sh +0 -0
  342. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/ui-templates.sh +0 -0
  343. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/ui.sh +0 -0
  344. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/uri.sh +0 -0
  345. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/lib/validate.sh +0 -0
  346. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/providers/echo.sh +0 -0
  347. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/providers/file.sh +0 -0
  348. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/providers/git.sh +0 -0
  349. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/providers/https.sh +0 -0
  350. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/providers/ui.sh +0 -0
  351. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/sdk/tool-error.sh +0 -0
  352. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/sdk/tool-sdk.sh +0 -0
  353. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.mcp-bash/sdk/ui-sdk.sh +0 -0
  354. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/prompts.json +0 -0
  355. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/resource-templates.json +0 -0
  356. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/resources.json +0 -0
  357. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/.registry/ui-resources.json +0 -0
  358. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/Makefile +0 -0
  359. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/README.md +0 -0
  360. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/completions/entity-name.sh +0 -0
  361. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/completions/list-name.sh +0 -0
  362. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/completions/status-value.sh +0 -0
  363. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/docs/DEBUGGING.md +0 -0
  364. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/icon.svg +0 -0
  365. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/cache.sh +0 -0
  366. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/cli-detect.sh +0 -0
  367. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/cli-gateway.sh +0 -0
  368. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/common.sh +0 -0
  369. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/entity-types.sh +0 -0
  370. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/lib/field-resolution.sh +0 -0
  371. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/mcp-publisher.lock +0 -0
  372. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/mcpb.conf +0 -0
  373. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/change-status/change-status.completion.sh +0 -0
  374. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/change-status/change-status.meta.json +0 -0
  375. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/change-status/change-status.txt +0 -0
  376. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/interaction-brief/interaction-brief.meta.json +0 -0
  377. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/interaction-brief/interaction-brief.txt +0 -0
  378. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-call/log-call.meta.json +0 -0
  379. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-call/log-call.txt +0 -0
  380. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +0 -0
  381. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +0 -0
  382. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-message/log-message.meta.json +0 -0
  383. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/log-message/log-message.txt +0 -0
  384. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/pipeline-review/pipeline-review.completion.sh +0 -0
  385. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/pipeline-review/pipeline-review.meta.json +0 -0
  386. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/pipeline-review/pipeline-review.txt +0 -0
  387. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +0 -0
  388. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/prepare-briefing/prepare-briefing.txt +0 -0
  389. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/warm-intro/warm-intro.meta.json +0 -0
  390. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/prompts/warm-intro/warm-intro.txt +0 -0
  391. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/providers/xaffinity.sh +0 -0
  392. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/data-model/data-model.md +0 -0
  393. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/data-model/data-model.meta.json +0 -0
  394. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/field-catalogs/field-catalogs.meta.json +0 -0
  395. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/field-catalogs/field-catalogs.sh +0 -0
  396. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/interaction-enums/interaction-enums.json +0 -0
  397. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/interaction-enums/interaction-enums.meta.json +0 -0
  398. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/me/me.meta.json +0 -0
  399. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/me/me.sh +0 -0
  400. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/me-person-id/me-person-id.meta.json +0 -0
  401. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/me-person-id/me-person-id.sh +0 -0
  402. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/query-guide/query-guide.meta.json +0 -0
  403. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/query-guide/query-guide.sh +0 -0
  404. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/saved-views/saved-views.meta.json +0 -0
  405. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/saved-views/saved-views.sh +0 -0
  406. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/workflow-config/workflow-config.meta.json +0 -0
  407. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/workflow-config/workflow-config.sh +0 -0
  408. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/workflows-guide/workflows-guide.meta.json +0 -0
  409. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/workflows-guide/workflows-guide.sh +0 -0
  410. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/xaffinity-field-catalogs.completion.sh +0 -0
  411. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/xaffinity-saved-views.completion.sh +0 -0
  412. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/resources/xaffinity-workflow-config.completion.sh +0 -0
  413. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.d/env.sh +0 -0
  414. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.d/health-checks.sh +0 -0
  415. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.d/policy.sh +0 -0
  416. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/server.json +0 -0
  417. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/test/README.md +0 -0
  418. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/test/run.sh +0 -0
  419. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/test/test_env_update_check.sh +0 -0
  420. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/test-progress.sh +0 -0
  421. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/discover-commands/tool.meta.json +0 -0
  422. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/discover-commands/tool.sh +0 -0
  423. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/execute-read-command/tool.meta.json +0 -0
  424. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/execute-read-command/tool.sh +0 -0
  425. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/execute-write-command/tool.meta.json +0 -0
  426. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/execute-write-command/tool.sh +0 -0
  427. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/get-entity-dossier/tool.meta.json +0 -0
  428. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/get-entity-dossier/tool.sh +0 -0
  429. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/get-file-url/tool.meta.json +0 -0
  430. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/get-file-url/tool.sh +0 -0
  431. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/query/tool.sh +0 -0
  432. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/read-xaffinity-resource/tool.meta.json +0 -0
  433. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/tools/read-xaffinity-resource/tool.sh +0 -0
  434. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/user-config.json +0 -0
  435. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/xaffinity-mcp-env.sh +0 -0
  436. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mcp/xaffinity-mcp.sh +0 -0
  437. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/mkdocs.yml +0 -0
  438. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/references/services.md +0 -0
  439. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/.claude-plugin/plugin.json +0 -0
  440. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/hooks/guard-env-read.sh +0 -0
  441. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/hooks/hooks.json +0 -0
  442. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/hooks/pre-xaffinity.sh +0 -0
  443. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/hooks/session-setup.sh +0 -0
  444. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/SKILL.md +0 -0
  445. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/files-and-writes.md +0 -0
  446. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/filtering.md +0 -0
  447. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/history-and-activity.md +0 -0
  448. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/interactions.md +0 -0
  449. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/query-guide.md +0 -0
  450. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/setup.md +0 -0
  451. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/query/test_cursor.py +0 -0
  452. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_company_create_dedup.py +0 -0
  453. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_company_ls_filter_rejection.py +0 -0
  454. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_formatters.py +0 -0
  455. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_output_formats_integration.py +0 -0
  456. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_person_create_dedup.py +0 -0
  457. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_person_ls_filter_rejection.py +0 -0
  458. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_filter_rejection.py +0 -0
  459. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_list_entry_relationships.py +0 -0
  460. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_list_export_parity.py +0 -0
  461. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_output_flattening.py +0 -0
  462. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_output_truncation.py +0 -0
  463. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cli/test_query_unreplied.py +0 -0
  464. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/conftest.py +0 -0
  465. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/.cowork-redact.json +0 -0
  466. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/README.md +0 -0
  467. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/fixtures/workdir-key/README.txt +0 -0
  468. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/fixtures/workdir-key/xaffinity-test-key +0 -0
  469. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/fixtures/workdir-nokey/README.txt +0 -0
  470. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/image/Dockerfile +0 -0
  471. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/image/fakeaff/build_fixtures.py +0 -0
  472. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/image/fakeaff/fixtures.json +0 -0
  473. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/image/fakeaff/server.py +0 -0
  474. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/image/xaffinity-wrapper.sh +0 -0
  475. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/privacy-allow.txt +0 -0
  476. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/record.sh +0 -0
  477. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/scenarios/company-lists-status.yaml +0 -0
  478. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/scenarios/hook-blocks-without-key.yaml +0 -0
  479. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/scenarios/no-key-skill-path.yaml +0 -0
  480. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/scenarios/status-history.yaml +0 -0
  481. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/sessions/no-key.yaml +0 -0
  482. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/cowork/sessions/with-key.yaml +0 -0
  483. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/field_write_mocks.py +0 -0
  484. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/openapi/mini_openapi.json +0 -0
  485. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/field_value_updated.json +0 -0
  486. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/list_entry_created.json +0 -0
  487. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/organization_created.json +0 -0
  488. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/organization_merged.json +0 -0
  489. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/person_created.json +0 -0
  490. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/fixtures/webhooks/unknown_event.json +0 -0
  491. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/README.md +0 -0
  492. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/conftest.py +0 -0
  493. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/setup_query_parity_data.py +0 -0
  494. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/test_cli_writes.py +0 -0
  495. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/test_query_parity_integration.py +0 -0
  496. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/test_sdk_reads.py +0 -0
  497. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/test_sdk_writes.py +0 -0
  498. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/integration/test_sdk_writes_runner.py +0 -0
  499. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/mcp/__init__.py +0 -0
  500. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/mcp/test_query_cursor.py +0 -0
  501. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/skill-evals/xaffinity-cli-usage-evals/evals.json +0 -0
  502. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/spec_guard.py +0 -0
  503. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
  504. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_api_coverage.py +0 -0
  505. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_api_key_file_formats.py +0 -0
  506. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_api_key_resolution.py +0 -0
  507. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_api_version.py +0 -0
  508. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_api_version_per_operation.py +0 -0
  509. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_async_file_download_streaming.py +0 -0
  510. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_batch_get.py +0 -0
  511. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_api_version.py +0 -0
  512. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_column_limiting.py +0 -0
  513. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_command_context.py +0 -0
  514. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_company_cmds_coverage.py +0 -0
  515. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_company_get.py +0 -0
  516. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_config_cmds.py +0 -0
  517. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_context_coverage.py +0 -0
  518. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_csv_export.py +0 -0
  519. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_date_params.py +0 -0
  520. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_date_utils.py +0 -0
  521. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_datetime_formatting.py +0 -0
  522. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_datetime_header_offsets.py +0 -0
  523. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_domain_linkification.py +0 -0
  524. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_dotenv_resolution.py +0 -0
  525. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_dropdown_field_writes.py +0 -0
  526. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_enriched_field_writes.py +0 -0
  527. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entity_field_writes.py +0 -0
  528. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entity_files_dump.py +0 -0
  529. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entry_field.py +0 -0
  530. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entry_field_batch_writes.py +0 -0
  531. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_entry_field_multi_value_limits.py +0 -0
  532. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_error_hints.py +0 -0
  533. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_error_rendering.py +0 -0
  534. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_history.py +0 -0
  535. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_history_bulk.py +0 -0
  536. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_options_and_transcripts.py +0 -0
  537. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_utils.py +0 -0
  538. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_utils_coverage.py +0 -0
  539. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_utils_set_phase.py +0 -0
  540. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_field_value_humanization.py +0 -0
  541. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_file_url.py +0 -0
  542. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_files_ls.py +0 -0
  543. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_files_read.py +0 -0
  544. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_get_interaction_dates.py +0 -0
  545. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_help_json.py +0 -0
  546. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_interaction_date_chunking.py +0 -0
  547. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_interaction_utils.py +0 -0
  548. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_json_safety.py +0 -0
  549. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_cmds_coverage.py +0 -0
  550. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_expand_interactions.py +0 -0
  551. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_export_entity_scope.py +0 -0
  552. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_export_field_refresh.py +0 -0
  553. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_list_export_truncation_meta.py +0 -0
  554. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_missing_coverage.py +0 -0
  555. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_multi_value_truncation_warnings.py +0 -0
  556. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_no_network_commands.py +0 -0
  557. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_notes_writes.py +0 -0
  558. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_opportunity_cmds.py +0 -0
  559. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_opportunity_cmds_coverage.py +0 -0
  560. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_pager_logic.py +0 -0
  561. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_person_cmds_coverage.py +0 -0
  562. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_person_get.py +0 -0
  563. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_plugin_manifest.py +0 -0
  564. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_pre_xaffinity_hook.py +0 -0
  565. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_progress_manager.py +0 -0
  566. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_aggregates.py +0 -0
  567. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_cmd.py +0 -0
  568. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_cmd_coverage.py +0 -0
  569. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_dates.py +0 -0
  570. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_executor.py +0 -0
  571. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_expand_interactions.py +0 -0
  572. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_filters.py +0 -0
  573. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_integration.py +0 -0
  574. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_parser.py +0 -0
  575. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_planner.py +0 -0
  576. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_safety.py +0 -0
  577. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_query_schema.py +0 -0
  578. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_rate_limit_rendering.py +0 -0
  579. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_rate_limit_throttle.py +0 -0
  580. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_reminders.py +0 -0
  581. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_render_coverage.py +0 -0
  582. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_resolve_coverage.py +0 -0
  583. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_resolve_url_parsing.py +0 -0
  584. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_result_summary.py +0 -0
  585. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_safe_field_writes.py +0 -0
  586. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_search.py +0 -0
  587. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_serialization.py +0 -0
  588. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_session_cache.py +0 -0
  589. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_session_setup_hook.py +0 -0
  590. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_set_phase_atomicity.py +0 -0
  591. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_types.py +0 -0
  592. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_unreplied.py +0 -0
  593. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_update_check.py +0 -0
  594. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_v1_only_cmds.py +0 -0
  595. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_v1_parsing.py +0 -0
  596. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_webhooks.py +0 -0
  597. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_cli_write_ops.py +0 -0
  598. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_client.py +0 -0
  599. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_companies_create_dedup.py +0 -0
  600. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_companies_filter_rejection.py +0 -0
  601. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_duplicates_connections.py +0 -0
  602. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_env_helpers.py +0 -0
  603. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_exceptions_coverage.py +0 -0
  604. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_field_resolver.py +0 -0
  605. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_field_service_caching.py +0 -0
  606. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_field_types_c4.py +0 -0
  607. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_field_value_type.py +0 -0
  608. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_field_values_get_value.py +0 -0
  609. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_file_batch_get.py +0 -0
  610. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_file_download_streaming.py +0 -0
  611. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_file_list_batch.py +0 -0
  612. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_file_upload_helpers_and_validation.py +0 -0
  613. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_files_upload_returning_files.py +0 -0
  614. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_files_v2.py +0 -0
  615. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_generate_mcp_command_registry.py +0 -0
  616. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_get_fields_filter_includes.py +0 -0
  617. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_get_fields_pagination.py +0 -0
  618. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_hidden_field_values.py +0 -0
  619. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_hooks.py +0 -0
  620. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_http_client_additional_coverage.py +0 -0
  621. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_http_client_remaining_coverage.py +0 -0
  622. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_inbound_webhooks.py +0 -0
  623. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_integration_smoke.py +0 -0
  624. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_interaction_date_validation.py +0 -0
  625. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_interactions_and_files_regressions.py +0 -0
  626. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_isodatetime.py +0 -0
  627. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_list_entry_membership_and_opportunities.py +0 -0
  628. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_list_term.py +0 -0
  629. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_lists_v2_writes.py +0 -0
  630. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_bundle_env_and_completions.py +0 -0
  631. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_cli_version_check.py +0 -0
  632. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_entity_dossier.py +0 -0
  633. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_gateway_limits.py +0 -0
  634. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_history_bulk_gateway.py +0 -0
  635. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_limits.py +0 -0
  636. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_query_cli_error.py +0 -0
  637. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_read_truncation.py +0 -0
  638. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_mcp_resource_scripts.py +0 -0
  639. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_models.py +0 -0
  640. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_models_v2_2026_fields.py +0 -0
  641. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_multi_value_limits.py +0 -0
  642. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_new_features.py +0 -0
  643. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_notes_v2.py +0 -0
  644. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_notes_v2_writes.py +0 -0
  645. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_opportunities_filter_rejection.py +0 -0
  646. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_org_reads.py +0 -0
  647. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_pagination_iterators.py +0 -0
  648. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_persons_create_dedup.py +0 -0
  649. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_persons_filter_rejection.py +0 -0
  650. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_public_api.py +0 -0
  651. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_query_pushdown.py +0 -0
  652. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_rate_limit_v2.py +0 -0
  653. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_raw_pipeline_hook_events.py +0 -0
  654. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_readonly_factory.py +0 -0
  655. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_reminder_list_batch.py +0 -0
  656. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_reminders_v2.py +0 -0
  657. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_requirements_additional.py +0 -0
  658. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_sdk_interaction_dates.py +0 -0
  659. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_search.py +0 -0
  660. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_search_v2.py +0 -0
  661. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_service_get_parameter_combinations.py +0 -0
  662. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_companies_coverage_gaps.py +0 -0
  663. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_dropdown_options.py +0 -0
  664. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_entity_field_updates.py +0 -0
  665. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_field_value_changes.py +0 -0
  666. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_list_entries_filter_paths.py +0 -0
  667. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_lists_additional_coverage.py +0 -0
  668. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_lists_coverage_gaps.py +0 -0
  669. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_opportunities_additional_coverage.py +0 -0
  670. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_opportunities_coverage_gaps.py +0 -0
  671. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
  672. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_persons_companies_additional_coverage.py +0 -0
  673. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_rate_limits_coverage_gaps.py +0 -0
  674. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_v1_only_async.py +0 -0
  675. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_services_v1_only_coverage_gaps.py +0 -0
  676. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_single_field_v2.py +0 -0
  677. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_small_modules_coverage.py +0 -0
  678. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_spec_guard.py +0 -0
  679. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_transport_and_readonly_mode.py +0 -0
  680. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_v1_association_parsing.py +0 -0
  681. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_v1_only_services_additional_coverage.py +0 -0
  682. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_v1_only_services_more_coverage.py +0 -0
  683. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_v2_request_bodies.py +0 -0
  684. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_validate_openapi_tool.py +0 -0
  685. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/test_webhooks_v2.py +0 -0
  686. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/unit/__init__.py +0 -0
  687. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tests/unit/test_exceptions.py +0 -0
  688. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/__init__.py +0 -0
  689. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/api_coverage.py +0 -0
  690. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/api_coverage_v1_snapshot.json +0 -0
  691. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/check_cli_patterns.py +0 -0
  692. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/generate_mcp_command_registry.py +0 -0
  693. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/generate_release_notes.py +0 -0
  694. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/generate_requirements_mapping.py +0 -0
  695. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/sync_mcp_bundle_env.py +0 -0
  696. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/sync_mcp_registry.py +0 -0
  697. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/sync_mcp_version.py +0 -0
  698. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/validate_mcp_registry_metadata.py +0 -0
  699. {affinity_sdk-2.0.2 → affinity_sdk-2.0.3}/tools/validate_openapi_models.py +0 -0
@@ -7,6 +7,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.0.3] - 2026-10-13
11
+
12
+ **Exception to semantic versioning** (the maintainer's call, as 2.0.2): some results change
13
+ (`list(filter=...)` pages, the local sort's order, date comparisons in filters). The
14
+ `### Changed` entries say how.
15
+
16
+ ### Changed
17
+
18
+ - **SDK list-entry filters go through Affinity's search:**
19
+ `lists.entries(id).list/pages/all/iter/get_first(filter=...)` send the part of the filter
20
+ Affinity's search can answer and check the whole filter locally, as `list export --filter`
21
+ does. Only when no part can go there (or the search is refused) is every entry read; that
22
+ case emits the new `ClientSideFilterWarning` (a `UserWarning`).
23
+ - **`list(filter=...)` returns the matches of one page read**, possibly fewer than `limit` (or
24
+ none), with a `next_cursor` that carries the filter: follow it, or use `iter()` for every
25
+ match. Before, it filtered only the first page and had no way to continue.
26
+ - **Filtered-read cursors are `xsearch2:`** (the filter travels as data, so multi-word field
27
+ names and dates round-trip) in the SDK, `list export`, and `company ls` / `person ls`;
28
+ 2.0.2's `xsearch1:` cursors still work.
29
+ - **Field values can be named by id in text filters** (`F.field("field-123")`,
30
+ `--filter 'field-123 = …'`), as `query` allows `fields.<id>`.
31
+ - **`query`'s local sort follows Affinity's order** (when Affinity can't sort, e.g. an
32
+ unsortable field or a refused search): ranked dropdowns sort by rank (not by text),
33
+ multi-value fields by their first item, and text case-insensitively ("apple" before
34
+ "Zeta"); empty values stay last in both directions. Fields named only in `orderBy` are now
35
+ fetched (a local sort used to see them empty). Grouped rows (`groupBy`) sort by their keys
36
+ as before.
37
+ - **Quantifier queries (`all`/`none`/`exists`) on companies and persons no longer always need
38
+ `--max-records`**: their `where` must test a field, which Affinity's search applies first;
39
+ when it matches at most 100 records the query runs, otherwise it stops and names the count.
40
+ `--dry-run` gives a number of API calls instead of "UNBOUNDED" (with `--max-records` too),
41
+ which also fixes the MCP query tool's timeout for these queries (it fell back to 120 s).
42
+ Validation errors found while the query runs exit 2 with `validation_error`, like those
43
+ found while planning.
44
+
45
+ ### Added
46
+
47
+ - **`server_filter=False`** on the list-entry `list/pages/all/iter/get_first` reads every entry
48
+ and filters locally (to compare or debug), and **`affinity.ClientSideFilterWarning`**.
49
+ - **More filters go to Affinity's search** (verified live): `starts_word` on single-company
50
+ fields, and `is_not_null` / `is_null` on location fields.
51
+
52
+ - **A team's members and accessible lists, every page** (V2, beta; API 2026-09-17+):
53
+ `teams.list|iter_members(team_id)` and `teams.list|iter_accessible_lists(team_id)`; CLI
54
+ `team members <id>` and `team lists <id>` (`team get` shows only the first 10).
55
+
56
+ ### Fixed
57
+
58
+ - **Dates compare as dates in `>`, `>=`, `<`, `<=` and between**, everywhere filters run
59
+ (`query`, `--filter`, `--expand-filter`, `company ls` / `person ls --filter`, and the SDK's
60
+ `affinity.filters`): relative dates (`-30d`, `today`) and ISO dates are compared with the
61
+ field's timestamp in UTC. Before, the text filter compared them as text, so
62
+ `Close > "-30d"` matched every dated entry. Equality stays textual (`= "today"` matches the
63
+ word). Timestamps with `Z` or long fractions parse on Python 3.10 too.
64
+ - **`list export --field X --filter "Y = …"`** returned no rows: the filter's fields are now
65
+ fetched even when `--field` leaves them out of the output.
66
+ - **`Team` reads `updatedAt`** (`updated_at`), and accepts the `membersPreview` /
67
+ `accessibleListsPreview` blocks under their own names too.
68
+
10
69
  ## [2.0.2] - 2026-10-13
11
70
 
12
71
  ### Changed (breaking)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: affinity-sdk
3
- Version: 2.0.2
3
+ Version: 2.0.3
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/
@@ -47,6 +47,7 @@ from .exceptions import (
47
47
  ApiVersionTooOldError,
48
48
  AuthenticationError,
49
49
  AuthorizationError,
50
+ ClientSideFilterWarning,
50
51
  CompanyMergedError,
51
52
  CompanyNotFoundError,
52
53
  ConfigurationError,
@@ -108,6 +109,7 @@ __all__ = [
108
109
  "AsyncAffinity",
109
110
  # Exceptions
110
111
  "AffinityError",
112
+ "ClientSideFilterWarning",
111
113
  "AuthenticationError",
112
114
  "AuthorizationError",
113
115
  "NotFoundError",
@@ -0,0 +1,5 @@
1
+ """The filter engine shared by the SDK and the CLI: WHERE clauses, date parsing, the split of a
2
+ filter into what Affinity's search can answer, and the ``--filter`` text conversion.
3
+
4
+ Private package: not part of the public SDK API.
5
+ """
@@ -1,7 +1,7 @@
1
1
  """Relative date parsing for query WHERE clauses.
2
2
 
3
3
  This module provides parsing for relative date strings like "-30d", "today", etc.
4
- It is CLI-only and NOT part of the public SDK API.
4
+ Private module: not part of the public SDK API (the CLI and the SDK share it).
5
5
  """
6
6
 
7
7
  from __future__ import annotations
@@ -113,17 +113,31 @@ def parse_date_value(value: str) -> datetime | None:
113
113
  pass
114
114
 
115
115
  # Try ISO date
116
- if ISO_DATE_PATTERN.match(value):
117
- try:
118
- # Handle with and without time component
119
- if "T" in value:
120
- return datetime.fromisoformat(value.replace("Z", "+00:00"))
121
- else:
122
- return datetime.fromisoformat(value)
123
- except ValueError:
124
- pass
125
-
126
- return None
116
+ return parse_iso_datetime(value)
117
+
118
+
119
+ _FRACTION = re.compile(r"(\.\d+)")
120
+
121
+
122
+ def parse_iso_datetime(value: object) -> datetime | None:
123
+ """An ISO 8601 date or date-time (``YYYY-MM-DD``, ``...THH:MM:SS[.fraction][Z|±HH:MM]``) as a
124
+ datetime, or ``None``. Tolerant of what Python 3.10's ``fromisoformat`` rejects: ``Z`` and
125
+ fractions that aren't 3 or 6 digits."""
126
+ if not isinstance(value, str) or not ISO_DATE_PATTERN.match(value.strip()):
127
+ return None
128
+ text = value.strip()
129
+ if text.endswith(("Z", "z")):
130
+ text = text[:-1] + "+00:00"
131
+ text = _FRACTION.sub(lambda m: (m.group(1) + "000000")[:7], text, count=1)
132
+ try:
133
+ return datetime.fromisoformat(text)
134
+ except ValueError:
135
+ return None
136
+
137
+
138
+ def as_utc(value: datetime) -> datetime:
139
+ """``value`` with a time zone: naive values are taken as UTC."""
140
+ return value if value.tzinfo is not None else value.replace(tzinfo=timezone.utc)
127
141
 
128
142
 
129
143
  def days_since(date: datetime, *, now: datetime | None = None) -> int:
@@ -4,13 +4,13 @@
4
4
  language written two ways; this turns the first into the second, so both go through the same
5
5
  server-side split (:mod:`.pushdown`). The text filter still runs locally exactly as before.
6
6
 
7
- This module is CLI-only and NOT part of the public SDK API.
7
+ Private module: not part of the public SDK API (the CLI and the SDK share it).
8
8
  """
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
- from ...compare import map_operator
13
- from ...filters import (
12
+ from ..compare import map_operator
13
+ from ..filters import (
14
14
  AndExpression,
15
15
  FieldComparison,
16
16
  FilterExpression,
@@ -18,7 +18,7 @@ from ...filters import (
18
18
  OrExpression,
19
19
  RawToken,
20
20
  )
21
- from .models import WhereClause
21
+ from .where import WhereClause
22
22
 
23
23
  # Row-level keys a list entry filter sees besides its fields (they aren't list fields).
24
24
  ROW_KEYS = frozenset(
@@ -9,7 +9,7 @@ A mapping is used only when it is in :data:`VERIFIED` — confirmed against the
9
9
  ``tools/search_golden.py`` (server count == local count on real data). Unverified mappings stay
10
10
  local.
11
11
 
12
- This module is CLI-only and NOT part of the public SDK API.
12
+ Private module: not part of the public SDK API (the CLI and the SDK share it).
13
13
  """
14
14
 
15
15
  from __future__ import annotations
@@ -21,11 +21,11 @@ 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
25
- from ...criteria import Condition, FilterGroup, filter_value_type
26
- from ...models.entities import DropdownOption, FieldMetadata
24
+ from ..compare import compare_values
25
+ from ..criteria import Condition, FilterGroup, filter_value_type
26
+ from ..models.entities import DropdownOption, FieldMetadata
27
27
  from .dates import parse_date_value
28
- from .models import WhereClause
28
+ from .where import WhereClause
29
29
 
30
30
  # (filter value type, server operator) pairs confirmed by tools/search_golden.py: no record the
31
31
  # local filter keeps was missing from the server's answer (5 lists, about 3,750 entries,
@@ -78,6 +78,12 @@ VERIFIED: frozenset[tuple[str, str]] = frozenset(
78
78
  ("dropdown-multi", "has-all-of"),
79
79
  ("dropdown-multi", "has-none-of"),
80
80
  ("number", "is-not-equal-to"),
81
+ # Fourth run (lists with single-company and location fields), 2026-10-13
82
+ ("company", "term"),
83
+ ("company", "is-not-empty"),
84
+ ("location", "is-not-empty"),
85
+ ("location-multi", "is-empty"),
86
+ ("location-multi", "is-not-empty"),
81
87
  }
82
88
  )
83
89
 
@@ -0,0 +1,305 @@
1
+ """Filtering list entries, companies and persons through Affinity's search, shared by the SDK
2
+ (``lists.entries(id).list/pages/all/iter(filter=...)``) and the CLI (``list export --filter``,
3
+ ``company ls`` / ``person ls --filter``).
4
+
5
+ - :func:`plan_filter` splits a text filter (or :class:`~affinity.filters.FilterExpression`)
6
+ into the search body Affinity can answer and the rest, which the caller re-checks locally.
7
+ - Next-page cursors carry the filter, so a cursor alone resumes a filtered read:
8
+ ``xsearch2:`` + base64 JSON ``{"k": "search"|"local", "u": next page URL, "b": search body,
9
+ "f": filter tree}``. ``k="search"`` re-sends ``b`` to ``u`` (a search's next page needs its
10
+ body); ``k="local"`` reads ``u`` (a plain page) and filters it locally. ``xsearch1:`` cursors
11
+ (filter as text, always a search) from 2.0.2 still decode.
12
+ - :class:`SearchCache` keeps fields, dropdown options and refused searches per list for a while.
13
+
14
+ Private module: not part of the public SDK API.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import base64
20
+ import json
21
+ import threading
22
+ import time
23
+ from collections.abc import Callable, Iterable, Sequence
24
+ from dataclasses import dataclass, field
25
+ from datetime import date, datetime
26
+ from typing import Any, Literal
27
+ from urllib.parse import urlparse
28
+
29
+ from ..criteria import SearchCriteria
30
+ from ..filters import (
31
+ AndExpression,
32
+ FieldComparison,
33
+ FilterExpression,
34
+ NotExpression,
35
+ OrExpression,
36
+ RawFilter,
37
+ RawToken,
38
+ parse,
39
+ )
40
+ from ..models.entities import DropdownOption, FieldMetadata
41
+ from .filter_text import ROW_KEYS, where_from_filter
42
+ from .pushdown import fields_index, split_where
43
+ from .where import WhereClause
44
+
45
+ CURSOR_V2 = "xsearch2:"
46
+ CURSOR_V1 = "xsearch1:"
47
+ CURSOR_PREFIXES = (CURSOR_V2, CURSOR_V1)
48
+ CACHE_TTL_SECONDS = 300.0
49
+
50
+ CursorKind = Literal["search", "local"]
51
+
52
+
53
+ # --- plan ---------------------------------------------------------------------------------------
54
+
55
+
56
+ @dataclass
57
+ class FilterPlan:
58
+ """What Affinity's search applies of a filter (``body``; ``None``: nothing) and the notes."""
59
+
60
+ body: dict[str, Any] | None
61
+ field_ids: list[str] = field(default_factory=list) # fields the filter tests
62
+ pushed: list[str] = field(default_factory=list)
63
+ local: list[str] = field(default_factory=list)
64
+ caveats: list[str] = field(default_factory=list)
65
+ errors: list[str] = field(default_factory=list)
66
+
67
+ @property
68
+ def complete(self) -> bool:
69
+ """Every condition went to the server."""
70
+ return self.body is not None and not self.local
71
+
72
+
73
+ def reject_raw_filters(expr: FilterExpression) -> None:
74
+ """``RawFilter`` can't be evaluated locally; refuse it anywhere in the tree."""
75
+ if isinstance(expr, RawFilter):
76
+ raise ValueError(
77
+ "A raw filter string can't filter list entries, companies or persons: "
78
+ "use a parsed filter (affinity.filters.parse or the F builder)"
79
+ )
80
+ for child in _children(expr):
81
+ reject_raw_filters(child)
82
+
83
+
84
+ def _children(expr: FilterExpression) -> list[FilterExpression]:
85
+ if isinstance(expr, (AndExpression, OrExpression)):
86
+ return [expr.left, expr.right]
87
+ if isinstance(expr, NotExpression):
88
+ return [expr.expr]
89
+ return []
90
+
91
+
92
+ def _field_paths(where: WhereClause) -> set[str]:
93
+ paths: set[str] = set()
94
+ if where.path and where.path.startswith("fields."):
95
+ paths.add(where.path.removeprefix("fields."))
96
+ for child in [*(where.and_ or []), *(where.or_ or [])]:
97
+ paths |= _field_paths(child)
98
+ if where.not_ is not None:
99
+ paths |= _field_paths(where.not_)
100
+ return paths
101
+
102
+
103
+ def referenced_field_names(expr: FilterExpression, row_keys: frozenset[str] = ROW_KEYS) -> set[str]:
104
+ """The field names (or ids) a filter tests; record attributes (``row_keys``) excluded."""
105
+ return _field_paths(where_from_filter(expr, row_keys))
106
+
107
+
108
+ def plan_filter(
109
+ expr: FilterExpression,
110
+ fields: Sequence[FieldMetadata],
111
+ options_for: Callable[[FieldMetadata], Sequence[DropdownOption]],
112
+ *,
113
+ row_keys: frozenset[str] = ROW_KEYS,
114
+ enriched: str = "or-empty",
115
+ ) -> FilterPlan:
116
+ """Split ``expr`` for these fields (pure: ``options_for`` supplies dropdown options)."""
117
+ where = where_from_filter(expr, row_keys)
118
+ split = split_where(where, fields, options_for, enriched=enriched)
119
+ index = fields_index(fields)
120
+ ids: list[str] = []
121
+ for name in sorted(_field_paths(where)):
122
+ meta = index.get(name) or index.get(name.lower())
123
+ if meta is not None and str(meta.id) not in ids:
124
+ ids.append(str(meta.id))
125
+ body = (
126
+ SearchCriteria(where=split.where, term=split.term, term_fields=split.term_fields).to_body()
127
+ if split.server_side
128
+ else None
129
+ )
130
+ return FilterPlan(
131
+ body=body,
132
+ field_ids=ids,
133
+ pushed=split.pushed,
134
+ local=split.local,
135
+ caveats=split.caveats,
136
+ errors=split.errors,
137
+ )
138
+
139
+
140
+ def dropdown_fields(expr: FilterExpression, fields: Sequence[FieldMetadata]) -> list[FieldMetadata]:
141
+ """The dropdown fields a filter tests (their options are needed to plan it)."""
142
+ index = fields_index(fields)
143
+ out: list[FieldMetadata] = []
144
+ for name in sorted(referenced_field_names(expr)):
145
+ meta = index.get(name) or index.get(name.lower())
146
+ value_type = str(getattr(meta.value_type, "value", meta.value_type)) if meta else ""
147
+ if meta is not None and value_type in ("dropdown", "ranked-dropdown", "dropdown-multi"):
148
+ out.append(meta)
149
+ return out
150
+
151
+
152
+ # --- filter tree (cursor payload) ---------------------------------------------------------------
153
+
154
+
155
+ def _value_to_json(value: Any) -> Any:
156
+ if isinstance(value, RawToken):
157
+ return {"t": "raw", "v": value.token}
158
+ if isinstance(value, datetime):
159
+ return {"t": "datetime", "v": value.isoformat()}
160
+ if isinstance(value, date):
161
+ return {"t": "date", "v": value.isoformat()}
162
+ if isinstance(value, (list, tuple)):
163
+ return {"t": "list", "v": [_value_to_json(v) for v in value]}
164
+ if value is None or isinstance(value, (str, bool, int, float)):
165
+ return {"t": "value", "v": value}
166
+ raise ValueError(f"Can't put a {type(value).__name__} filter value in a cursor")
167
+
168
+
169
+ def _value_from_json(obj: Any) -> Any:
170
+ if not isinstance(obj, dict) or set(obj) != {"t", "v"}:
171
+ raise ValueError("bad value")
172
+ tag, v = obj["t"], obj["v"]
173
+ if tag == "raw":
174
+ if v != "*":
175
+ raise ValueError("bad raw token")
176
+ return RawToken("*")
177
+ if tag == "datetime" and isinstance(v, str):
178
+ return datetime.fromisoformat(v)
179
+ if tag == "date" and isinstance(v, str):
180
+ return date.fromisoformat(v)
181
+ if tag == "list" and isinstance(v, list):
182
+ return [_value_from_json(x) for x in v]
183
+ if tag == "value" and (v is None or isinstance(v, (str, bool, int, float))):
184
+ return v
185
+ raise ValueError("bad value")
186
+
187
+
188
+ def filter_to_json(expr: FilterExpression) -> Any:
189
+ """A filter expression as JSON data (round-trips, unlike ``to_string``)."""
190
+ if isinstance(expr, FieldComparison):
191
+ return {
192
+ "cmp": [expr.field_name, expr.operator, _value_to_json(expr.value)],
193
+ }
194
+ if isinstance(expr, AndExpression):
195
+ return {"and": [filter_to_json(expr.left), filter_to_json(expr.right)]}
196
+ if isinstance(expr, OrExpression):
197
+ return {"or": [filter_to_json(expr.left), filter_to_json(expr.right)]}
198
+ if isinstance(expr, NotExpression):
199
+ return {"not": filter_to_json(expr.expr)}
200
+ raise ValueError(f"Can't put a {type(expr).__name__} in a cursor")
201
+
202
+
203
+ def filter_from_json(obj: Any, depth: int = 0) -> FilterExpression:
204
+ """The filter expression :func:`filter_to_json` made; ``ValueError`` for anything else."""
205
+ if depth > 64 or not isinstance(obj, dict) or len(obj) != 1:
206
+ raise ValueError("bad filter")
207
+ ((key, value),) = obj.items()
208
+ if key == "cmp" and isinstance(value, list) and len(value) == 3:
209
+ name, operator, raw = value
210
+ if not isinstance(name, str) or not isinstance(operator, str):
211
+ raise ValueError("bad comparison")
212
+ return FieldComparison(name, operator, _value_from_json(raw))
213
+ if key in ("and", "or") and isinstance(value, list) and len(value) == 2:
214
+ left, right = (filter_from_json(v, depth + 1) for v in value)
215
+ return AndExpression(left, right) if key == "and" else OrExpression(left, right)
216
+ if key == "not":
217
+ return NotExpression(filter_from_json(value, depth + 1))
218
+ raise ValueError("bad filter")
219
+
220
+
221
+ # --- cursors ------------------------------------------------------------------------------------
222
+
223
+
224
+ @dataclass(frozen=True)
225
+ class SearchCursor:
226
+ """A decoded filtered-read cursor."""
227
+
228
+ kind: CursorKind
229
+ url: str
230
+ body: dict[str, Any] | None
231
+ filter: FilterExpression
232
+
233
+
234
+ def encode_cursor(
235
+ kind: CursorKind, url: str, body: dict[str, Any] | None, expr: FilterExpression
236
+ ) -> str:
237
+ payload = {"k": kind, "u": url, "b": body, "f": filter_to_json(expr)}
238
+ raw = json.dumps(payload, separators=(",", ":")).encode()
239
+ return CURSOR_V2 + base64.urlsafe_b64encode(raw).decode().rstrip("=")
240
+
241
+
242
+ def is_filter_cursor(cursor: str | None) -> bool:
243
+ return cursor is not None and cursor.startswith(CURSOR_PREFIXES)
244
+
245
+
246
+ def decode_cursor(cursor: str, *, path_suffixes: Iterable[str]) -> SearchCursor | None:
247
+ """The filtered-read cursor in ``cursor`` (``None`` when it's a plain page URL). The
248
+ cursor is user input: anything malformed, or a cursor for another kind of record (its URL
249
+ path must end with one of ``path_suffixes``), raises ``ValueError``."""
250
+ if not is_filter_cursor(cursor):
251
+ return None
252
+ prefix = CURSOR_V2 if cursor.startswith(CURSOR_V2) else CURSOR_V1
253
+ encoded = cursor.removeprefix(prefix)
254
+ try:
255
+ data = json.loads(base64.urlsafe_b64decode(encoded + "=" * (-len(encoded) % 4)))
256
+ except (ValueError, TypeError) as e:
257
+ raise ValueError("This cursor is damaged: start the read again without it") from e
258
+ if not isinstance(data, dict) or not isinstance(data.get("u"), str):
259
+ raise ValueError("This cursor is damaged: start the read again without it")
260
+ url = data["u"]
261
+ if not any(urlparse(url).path.endswith(s) for s in path_suffixes):
262
+ raise ValueError("This cursor belongs to a different list or kind of record")
263
+ if prefix == CURSOR_V1:
264
+ body, text = data.get("b"), data.get("f")
265
+ if not isinstance(body, dict) or not isinstance(text, str):
266
+ raise ValueError("This cursor is damaged: start the read again without it")
267
+ return SearchCursor("search", url, body, parse(text))
268
+ kind, body = data.get("k"), data.get("b")
269
+ if kind not in ("search", "local") or (kind == "search" and not isinstance(body, dict)):
270
+ raise ValueError("This cursor is damaged: start the read again without it")
271
+ return SearchCursor(
272
+ kind, url, body if kind == "search" else None, filter_from_json(data.get("f"))
273
+ )
274
+
275
+
276
+ # --- cache --------------------------------------------------------------------------------------
277
+
278
+
279
+ class SearchCache:
280
+ """Per-client cache for planning searches: a list's fields (with filterability), dropdown
281
+ options, and lists whose search was refused (403 / 404 / unsupported). Entries expire
282
+ after ``ttl`` seconds; races only cost a duplicate fetch."""
283
+
284
+ def __init__(self, ttl: float = CACHE_TTL_SECONDS) -> None:
285
+ self._ttl = ttl
286
+ self._data: dict[tuple[str, ...], tuple[float, Any]] = {}
287
+ self._lock = threading.Lock()
288
+
289
+ def get(self, key: tuple[str, ...]) -> Any | None:
290
+ with self._lock:
291
+ hit = self._data.get(key)
292
+ if hit is None or hit[0] < time.monotonic():
293
+ self._data.pop(key, None)
294
+ return None
295
+ return hit[1]
296
+
297
+ def put(self, key: tuple[str, ...], value: Any) -> None:
298
+ with self._lock:
299
+ self._data[key] = (time.monotonic() + self._ttl, value)
300
+
301
+ def drop_scope(self, scope: str) -> None:
302
+ """Forget everything cached for one list (or entity type), e.g. after a 400."""
303
+ with self._lock:
304
+ for key in [k for k in self._data if k[1:2] == (scope,)]:
305
+ del self._data[key]
@@ -0,0 +1,108 @@
1
+ """WHERE clauses: the filter language's structured form (``query``'s JSON ``where``; the
2
+ ``--filter`` text converts to it). Shared by the SDK's server-side filtering and the CLI.
3
+
4
+ Private module: not part of the public SDK API.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Literal
10
+
11
+ from pydantic import BaseModel, ConfigDict, Field
12
+
13
+ __all__ = ["ExistsClause", "FilterCondition", "QuantifierClause", "WhereClause"]
14
+
15
+
16
+ class FilterCondition(BaseModel):
17
+ """A single filter condition.
18
+
19
+ Examples:
20
+ {"path": "email", "op": "contains", "value": "@acme.com"}
21
+ {"path": "createdAt", "op": "gt", "value": "-30d"}
22
+ {"path": "companies._count", "op": "gte", "value": 2}
23
+ """
24
+
25
+ model_config = ConfigDict(extra="forbid")
26
+
27
+ path: str | None = None
28
+ expr: dict[str, Any] | None = None
29
+ op: Literal[
30
+ "eq",
31
+ "neq",
32
+ "gt",
33
+ "gte",
34
+ "lt",
35
+ "lte",
36
+ "contains",
37
+ "starts_with",
38
+ "in",
39
+ "between",
40
+ "is_null",
41
+ "is_not_null",
42
+ "contains_any",
43
+ "contains_all",
44
+ "starts_word",
45
+ ]
46
+ value: Any = None
47
+
48
+
49
+ class QuantifierClause(BaseModel):
50
+ """Quantifier clause for 'all' or 'none' predicates.
51
+
52
+ Examples:
53
+ {"all": {"path": "interactions", "where": {"path": "type", "op": "eq", "value": "MEETING"}}}
54
+ """
55
+
56
+ model_config = ConfigDict(extra="forbid")
57
+
58
+ path: str
59
+ where: WhereClause
60
+
61
+
62
+ class ExistsClause(BaseModel):
63
+ """EXISTS subquery clause.
64
+
65
+ Examples:
66
+ {"exists": {"from": "interactions", "via": "personId", "where": {...}}}
67
+ """
68
+
69
+ model_config = ConfigDict(extra="forbid")
70
+
71
+ from_: str = Field(..., alias="from")
72
+ via: str | None = None
73
+ where: WhereClause | None = None
74
+
75
+
76
+ class WhereClause(BaseModel):
77
+ """WHERE clause supporting compound conditions.
78
+
79
+ Can be:
80
+ - A single condition: {"path": "x", "op": "eq", "value": "y"}
81
+ - Compound: {"and": [...]} or {"or": [...]}
82
+ - Negation: {"not": {...}}
83
+ - Quantifiers: {"all": {...}} or {"none": {...}}
84
+ - Existence: {"exists": {...}}
85
+ """
86
+
87
+ model_config = ConfigDict(extra="forbid", populate_by_name=True)
88
+
89
+ # Single condition fields
90
+ path: str | None = None
91
+ expr: dict[str, Any] | None = None
92
+ op: str | None = None
93
+ value: Any = None
94
+
95
+ # Compound conditions
96
+ and_: list[WhereClause] | None = Field(None, alias="and")
97
+ or_: list[WhereClause] | None = Field(None, alias="or")
98
+ not_: WhereClause | None = Field(None, alias="not")
99
+
100
+ # Quantifiers
101
+ all_: QuantifierClause | None = Field(None, alias="all")
102
+ none_: QuantifierClause | None = Field(None, alias="none")
103
+
104
+ # Existence
105
+ exists_: ExistsClause | None = Field(None, alias="exists")
106
+
107
+
108
+ WhereClause.model_rebuild()
@@ -27,7 +27,7 @@ from ..csv_utils import write_csv_to_stdout
27
27
  from ..decorators import category, destructive, progress_capable
28
28
  from ..entity_search import COMPANY_KEYS, filtered_ls
29
29
  from ..errors import CLIError
30
- from ..list_search import SEARCH_CURSOR_PREFIX
30
+ from ..list_search import is_filter_cursor
31
31
  from ..mcp_limits import apply_mcp_limits
32
32
  from ..options import csv_output_options, csv_suboption_callback, output_options
33
33
  from ..progress import ProgressManager, ProgressSettings
@@ -433,7 +433,7 @@ def company_ls(
433
433
  )
434
434
 
435
435
  # --filter (or a cursor from a filtered run): Affinity's search filters on its side
436
- if filter_expr is not None or (cursor or "").startswith(SEARCH_CURSOR_PREFIX):
436
+ if filter_expr is not None or is_filter_cursor(cursor):
437
437
  found, next_token = filtered_ls(
438
438
  client.companies,
439
439
  entity="company",