affinity-sdk 2.0.6__tar.gz → 2.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CHANGELOG.md +63 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/PKG-INFO +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/pushdown.py +104 -8
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/company_cmds.py +10 -3
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/list_cmds.py +100 -54
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/person_cmds.py +10 -3
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/entity_search.py +4 -3
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/options.py +24 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/executor.py +18 -6
- affinity_sdk-2.0.8/affinity/cli/query/pushdown.py +25 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/compare.py +72 -3
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/commands.md +6 -6
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/filtering.md +30 -12
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/query-command.md +4 -4
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/query-language.md +2 -2
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/plugin.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/SKILL.md +4 -4
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/filter-operators.md +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/commands.generated.json +10 -6
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/CHANGELOG.md +41 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/COMPATIBILITY +16 -2
- affinity_sdk-2.0.8/mcp/VERSION +1 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cli-gateway.sh +10 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.md +5 -5
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/requirements.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/server.meta.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.meta.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/query/tool.meta.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/.claude-plugin/plugin.json +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/pre-xaffinity.sh +2 -2
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/session-setup.sh +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/SKILL.md +3 -2
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/filtering.md +17 -6
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/query-guide.md +15 -7
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/setup.md +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/pyproject.toml +1 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/company-lists-status.cassette.json +89 -89
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/hook-blocks-without-key.cassette.json +66 -66
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/cassettes/no-key-skill-path.cassette.json +105 -104
- affinity_sdk-2.0.8/tests/cowork/cassettes/status-history.cassette.json +469 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_ls_server_filter.py +187 -0
- affinity_sdk-2.0.8/tests/test_cli_list_export_server_filter.py +661 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_executor.py +87 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_server_filter.py +191 -5
- affinity_sdk-2.0.8/tests/test_cli_repeated_filter.py +90 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_compare.py +2 -1
- affinity_sdk-2.0.8/tests/test_compare_entity_ids.py +159 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_entries_server_filter.py +81 -1
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_must_fix.py +25 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_query_pushdown.py +231 -1
- affinity_sdk-2.0.8/tools/search_golden.py +478 -0
- affinity_sdk-2.0.6/affinity/cli/query/pushdown.py +0 -12
- affinity_sdk-2.0.6/mcp/VERSION +0 -1
- affinity_sdk-2.0.6/tests/cowork/cassettes/status-history.cassette.json +0 -462
- affinity_sdk-2.0.6/tests/test_cli_list_export_server_filter.py +0 -216
- affinity_sdk-2.0.6/tools/search_golden.py +0 -238
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.claude-plugin/marketplace.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.cursor/rules/test-data-privacy.mdc +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.editorconfig +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.env.example +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.gitattributes +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/CODEOWNERS +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/PULL_REQUEST_TEMPLATE/release.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/dependabot.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/labels.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/mcp-release-install-footer.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/pull_request_template.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/release-install-footer.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/ci.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/cowork-replay.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/docs.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/labels.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/linkcheck.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/openapi-validation.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/plugin-build.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/plugin-release.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/release-detect.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/release.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.github/workflows/version-check.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.gitignore +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/.pre-commit-config.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/AGENTS.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CODE_OF_CONDUCT.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/CONTRIBUTING.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/LICENSE +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/README.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/SECURITY.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/VERSIONING.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/filter_text.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_filtering/where.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_internal/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/_internal/keyfile.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/api_versions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/__main__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/_update_worker.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/async_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/click_compat.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_field.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_dump.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_read.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_entity_files_upload.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_list_entry_fields.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_org_reads.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_search_common.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/_v1_parsing.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/completion_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/config_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/discovery_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/entry_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/field_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/file_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/file_url_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/interaction_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/note_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/opportunity_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/org_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/org_read_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/query_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/relationship_strength_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/reminder_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/resolve_url_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/session_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/task_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/transcript_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/version_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/webhook_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/commands/whoami_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/config.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/confirm.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/constants.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/context.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/csv_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/date_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/decorators.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/errors.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/field_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/formatters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/help_json.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/interaction_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/list_search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/logging.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/main.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/mcp_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/paths.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/progress.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/aggregates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/cursor.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/exceptions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/filter_text.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/filters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/models.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/output.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/parser.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/planner.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/progress.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/query/schema.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/render.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/resolve.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/resolvers.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/results.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/runner.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/serialization.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/session_cache.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/types.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/cli/update_check.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/client.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/http.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/clients/pipeline.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/criteria.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/downloads.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/exceptions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/field_resolve_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/field_resolver.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/filters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/hooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/inbound_webhooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/discovery.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/entities.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/interactions_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/org.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/pagination.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/rate_limit_snapshot.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/relationships_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/secondary.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/transcripts.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/models/types.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/policies.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/progress.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/py.typed +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_batch_interactions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_discovery.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_dropdown_options.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_field_listing.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_field_updates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_note_html.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_org_reads.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_single_field.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/_v2_filters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/companies.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/lists.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/opportunities.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/org.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/persons.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/rate_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/reminders.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/tasks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/transcripts.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/v1_only.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/services/webhooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/affinity/types.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/codecov.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/cli-development-guide.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/ai-integrations/index.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/changelog.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/index.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli/scripting.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/cli-reference.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/examples.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/getting-started.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/glossary.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/affinity-official-mcp-comparison.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/api-versions-and-routing.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/api-versions.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/authentication.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/claude-code-plugins.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/configuration.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/csv-export.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/datetime-handling.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/debugging-hooks.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/errors-and-retries.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/field-types-and-values.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/field-values.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/ids-and-types.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/migrating-to-2.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/models.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/opportunity-associations.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/pagination.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/performance.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/rate-limits.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/sync-vs-async.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/guides/webhooks.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/index.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/mcp/index.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/api-coverage.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/client.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/exceptions.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/filters.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/models.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/companies.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/lists.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/opportunities.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/persons.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/reminders.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/tasks.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/teams-users.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/transcripts.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/auth.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/field-values.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/fields.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/files.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/interactions.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/notes.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/v1/relationships.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/services/webhooks.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/reference/types.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/docs/public/troubleshooting.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/advanced_usage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/async_lifecycle.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/basic_usage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/filter_builder.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/hooks_debugging.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/list_management.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/resolve_helpers.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/examples/task_polling.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/.gitignore +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/pipeline-history/SKILL.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/include-expand.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/output-formats.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/skills/query-language/references/quantifiers.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.claude-plugin/xaffinity-mcp.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.gitignore +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/VERSION +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/bin/mcp-bash +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/lifecycle.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/logging.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/ping.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/prompts.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/resources.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/roots.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/handlers/tools.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/auth.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/capabilities.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/common.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/cli/health.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/core.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/elicitation.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/file_read.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/handler_helpers.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/hash.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ids.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/io.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/json.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/lock.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/logging.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/meta_env.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/paginate.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/path.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/policy.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress-passthrough.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/progress.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/prompts.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/registry.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/require.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_content.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_match.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resource_providers.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/resources.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/roots.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/rpc.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/runtime.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/spec.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/timeout.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/tools_policy.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui-templates.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/ui.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/uri.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/lib/validate.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/echo.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/file.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/git.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/https.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/providers/ui.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-error.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/tool-sdk.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/sdk/ui-sdk.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.mcp-bash/vendor.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/mcp-commands.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/prompts.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/resource-templates.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/resources.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/.registry/ui-resources.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/Makefile +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/README.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/entity-name.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/list-name.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/completions/status-value.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/docs/DEBUGGING.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/icon.svg +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cache.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/cli-detect.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/common.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/entity-types.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/lib/field-resolution.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcp-bash.lock +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcp-publisher.lock +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/mcpb.conf +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/change-status/change-status.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/interaction-brief/interaction-brief.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-call/log-call.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/log-message/log-message.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/pipeline-review/pipeline-review.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/prepare-briefing/prepare-briefing.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/prompts/warm-intro/warm-intro.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/providers/xaffinity.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/data-model/data-model.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/field-catalogs/field-catalogs.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/interaction-enums/interaction-enums.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me/me.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me/me.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/me-person-id/me-person-id.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/query-guide/query-guide.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/saved-views/saved-views.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflow-config/workflow-config.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/workflows-guide/workflows-guide.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-field-catalogs.completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-saved-views.completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/resources/xaffinity-workflow-config.completion.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/env.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/health-checks.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.d/policy.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/server.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/README.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/run.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test/test_env_update_check.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/test-progress.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/discover-commands/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-read-command/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/execute-write-command/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-entity-dossier/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/get-file-url/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/query/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.meta.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/tools/read-xaffinity-resource/tool.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/user-config.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp-env.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mcp/xaffinity-mcp.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/mkdocs.yml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/plugin.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/references/services.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/guard-env-read.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/hooks/hooks.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/files-and-writes.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/history-and-activity.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/plugins/xaffinity-cli/skills/xaffinity-cli-usage/references/interactions.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/query/test_cursor.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_company_create_dedup.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_company_ls_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_formatters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_output_formats_integration.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_person_create_dedup.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_person_ls_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_list_entry_relationships.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_list_export_parity.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_output_flattening.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_output_truncation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cli/test_query_unreplied.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/conftest.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/.cowork-redact.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/README.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/README.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-key/xaffinity-test-key +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/fixtures/workdir-nokey/README.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/Dockerfile +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/build_fixtures.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/fixtures.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/fakeaff/server.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/image/xaffinity-wrapper.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/privacy-allow.txt +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/record.sh +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/company-lists-status.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/hook-blocks-without-key.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/no-key-skill-path.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/scenarios/status-history.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/sessions/no-key.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/cowork/sessions/with-key.yaml +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/field_write_mocks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/openapi/mini_openapi.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/field_value_updated.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/list_entry_created.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_created.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/organization_merged.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/person_created.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/fixtures/webhooks/unknown_event.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/README.md +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/conftest.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/setup_query_parity_data.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_cli_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_query_parity_integration.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_reads.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/integration/test_sdk_writes_runner.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/mcp/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/mcp/test_query_cursor.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/skill-evals/xaffinity-cli-usage-evals/evals.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/spec_guard.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_key_file_formats.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_key_resolution.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_version.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_api_version_per_operation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_async_file_download_streaming.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_batch_get.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_api_version.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_column_limiting.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_command_context.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_commands_must_fix.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_company_cmds_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_company_get.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_config_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_context_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_csv_export.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_date_params.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_date_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_datetime_formatting.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_datetime_header_offsets.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_domain_linkification.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_dotenv_resolution.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_dropdown_field_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_enriched_field_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_field_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entity_files_dump.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_batch_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_entry_field_multi_value_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_error_hints.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_error_rendering.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history_bulk.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_history_deleted_options.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_options_and_transcripts.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_utils_set_phase.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_field_value_humanization.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_file_url.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_files_ls.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_files_read.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_get_interaction_dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_help_json.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_interaction_date_chunking.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_interaction_utils.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_json_safety.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_cmds_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_expand_interactions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_entity_scope.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_field_refresh.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_filter_safety.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_list_export_truncation_meta.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_missing_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_multi_value_truncation_warnings.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_no_network_commands.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_notes_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_opportunity_cmds_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_org.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_page_size_validation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_pager_logic.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_person_cmds_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_person_get.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_plugin_manifest.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_pre_xaffinity_hook.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_progress_manager.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_aggregates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_cmd_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_expand_interactions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_filters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_integration.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_must_fix.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_parser.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_planner.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_review_fixes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_safety.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_query_schema.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_rendering.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_rate_limit_throttle.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_reminders.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_render_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_resolve_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_resolve_url_parsing.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_result_summary.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_safe_field_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_serialization.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_session_cache.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_session_setup_hook.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_set_phase_atomicity.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_types.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_unreplied.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_update_check.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_v1_only_cmds.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_v1_parsing.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_webhooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_cli_write_ops.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_client.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_companies_create_dedup.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_companies_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_duplicates_connections.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_env_helpers.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_exceptions_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_resolver.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_service_caching.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_types_c4.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_value_type.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_field_values_get_value.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_batch_get.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_download_streaming.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_list_batch.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_file_upload_helpers_and_validation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_files_upload_returning_files.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_files_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_filters.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_generate_mcp_command_registry.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_fields_filter_includes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_fields_pagination.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_get_first.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_hidden_field_values.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_hooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_http_client_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_http_client_remaining_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_inbound_webhooks.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_integration_smoke.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_interaction_date_validation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_interactions_and_files_regressions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_isodatetime.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_entry_membership_and_opportunities.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_list_term.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_lists_v2_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_bundle_env_and_completions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_cli_version_check.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_entity_dossier.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_gateway_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_history_bulk_gateway.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_query_cli_error.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_read_truncation.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_mcp_resource_scripts.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_models.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_models_v2_2026_fields.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_multi_value_limits.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_new_features.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_notes_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_notes_v2_writes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_opportunities_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_org_reads.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_pagination_iterators.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_persons_create_dedup.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_persons_filter_rejection.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_public_api.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_rate_limit_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_raw_pipeline_hook_events.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_readonly_factory.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_reminder_list_batch.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_reminders_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_requirements_additional.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_review_fixes_sdk_cli.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_sdk_interaction_dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_sdk_must_fix.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_search.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_search_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_service_get_parameter_combinations.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_batch_get_interaction_dates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_companies_coverage_gaps.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_dropdown_options.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_entity_field_updates.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_entity_list_entries.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_field_value_changes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_list_entries_filter_paths.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_lists_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_lists_coverage_gaps.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_coverage_gaps.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_pages_cursor_guard.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_persons_companies_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_rate_limits_coverage_gaps.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_v1_only_async.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_services_v1_only_coverage_gaps.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_single_field_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_small_modules_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_spec_guard.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_teams_users_feedback.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_transport_and_readonly_mode.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_association_parsing.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_only_services_additional_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v1_only_services_more_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_v2_request_bodies.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_validate_openapi_tool.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/test_webhooks_v2.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/unit/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tests/unit/test_exceptions.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/__init__.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/api_coverage_v1_snapshot.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/check_cli_patterns.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_mcp_command_registry.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_release_notes.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/generate_requirements_mapping.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2024-01-01.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-07-15.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/openapi_snapshots/2026-09-17.json +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_bundle_env.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_registry.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/sync_mcp_version.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/validate_mcp_registry_metadata.py +0 -0
- {affinity_sdk-2.0.6 → affinity_sdk-2.0.8}/tools/validate_openapi_models.py +0 -0
|
@@ -5,6 +5,69 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.8] - 2026-11-05
|
|
9
|
+
|
|
10
|
+
**Exception to semantic versioning** (as 2.0.2–2.0.7): one fix changes which rows a filter
|
|
11
|
+
returns. It is marked **Behavior change**.
|
|
12
|
+
|
|
13
|
+
### Highlights
|
|
14
|
+
|
|
15
|
+
Filters on a person or company field by id (`Owner = 12345`) now run on Affinity's side for list
|
|
16
|
+
entries, so `list export` needs no `--all` and downloads only the matching rows. A number on a
|
|
17
|
+
record reference is its id only.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Behavior change (correctness fix). CLI and SDK (`--filter`, `query`, `affinity.filters`,
|
|
22
|
+
`list(filter=...)`): an integer or 1–20 digits on a person, company or other record-reference
|
|
23
|
+
field matches the record's id only.** It no longer matches a record whose name is those digits;
|
|
24
|
+
use `starts_word` to find such a name. (As before, a reference with no name, such as a person
|
|
25
|
+
without a first and last name or a company with an empty name, can't be matched by id.)
|
|
26
|
+
- CLI and SDK: on list entries, `=` and `in` with record ids on a person or company field, and
|
|
27
|
+
`=`, `in`, `has_any` and `has_all` with ids on a multi-person or multi-company field, go to
|
|
28
|
+
Affinity's search. Such filters need no `--all` / `--max-results` and download only matching
|
|
29
|
+
rows. Ids above 2147483647, names, `!=`, enriched person and company fields, and filters on
|
|
30
|
+
`company ls` / `person ls` / `query` from companies or persons are still checked locally.
|
|
31
|
+
- CLI: a `starts_word` with no letter (`starts_word "360"`) is checked locally instead of being
|
|
32
|
+
sent as Affinity's name search. On `list export` it needs a scope flag; on `company ls`,
|
|
33
|
+
`person ls` and `query` from companies or persons it needs another field condition (or use
|
|
34
|
+
`--query`).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- CLI: `list export --filter` with a filter Affinity's search refuses (for example a key without
|
|
39
|
+
the "Export data from Lists" permission), run without `--all`, `--max-results` or
|
|
40
|
+
`--first-page-only`, exits 2 before any output. It used to print only the first page, as if it
|
|
41
|
+
were the whole result. `details.refused` carries Affinity's reason.
|
|
42
|
+
|
|
43
|
+
## [2.0.7] - 2026-11-03
|
|
44
|
+
|
|
45
|
+
**Exception to semantic versioning** (as 2.0.2–2.0.6): two fixes change which rows a filter
|
|
46
|
+
returns. Each is marked **Behavior change**.
|
|
47
|
+
|
|
48
|
+
### Highlights
|
|
49
|
+
|
|
50
|
+
A repeated `--filter` now combines its conditions instead of keeping only the last one, and a
|
|
51
|
+
person or company field filtered by id (`Owner = 26229794`) matches that person instead of
|
|
52
|
+
nothing.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- **Behavior change (correctness fix). CLI: repeated `--filter` values are ANDed** on
|
|
57
|
+
`list export`, `company ls` and `person ls`, and so are repeated `list export --expand-filter`
|
|
58
|
+
values. Only the last one used to apply, and the others were dropped without a warning, so such
|
|
59
|
+
runs returned rows that didn't match the earlier conditions: re-run them. `--filter A --filter B`
|
|
60
|
+
is `(A) & (B)`; for OR, use `|` inside one value. Each repeated value must be a complete
|
|
61
|
+
expression on its own. (The MCP server refused a repeated `--filter`, so MCP calls weren't
|
|
62
|
+
affected.)
|
|
63
|
+
- **Behavior change (correctness fix). CLI and SDK: a person or company field compared with a
|
|
64
|
+
number matches the record's id.** `Owner = 26229794` (and `in`, `has_any`, `has_all`) in
|
|
65
|
+
`--filter`, `query` and `affinity.filters` compared the name with "26229794" and matched nothing,
|
|
66
|
+
without a warning (`!=` matched every row). It now matches that person's id, and names still
|
|
67
|
+
match as before. Other record references, such as lists, match their id too. Re-run filters that
|
|
68
|
+
used ids. A reference with no name (a person without a first and last name, a company with an
|
|
69
|
+
empty name) still can't be matched by id.
|
|
70
|
+
|
|
8
71
|
## [2.0.6] - 2026-10-14
|
|
9
72
|
|
|
10
73
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: affinity-sdk
|
|
3
|
-
Version: 2.0.
|
|
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
|
|
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
|
|
342
|
-
|
|
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
|
|
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
|
-
|
|
436
|
+
if isinstance(value, str) and re.fullmatch(r"[0-9 ]+", value.strip()):
|
|
437
|
+
ctx.local.append(f"{_describe(w)}: a number isn't sent as a name search")
|
|
438
|
+
else:
|
|
439
|
+
ctx.local.append(f"{_describe(w)}: one name search per query (the rest stay local)")
|
|
403
440
|
return None
|
|
441
|
+
if vt in _NAMED and op in ("eq", "in", "has_any", "has_all"):
|
|
442
|
+
return _reference(w, meta, vt, ctx)
|
|
404
443
|
if vt in _DROPDOWN:
|
|
405
444
|
return _dropdown(w, meta, vt, ctx)
|
|
406
445
|
if vt in ("dropdown-multi", "filterable-text-multi"):
|
|
@@ -423,6 +462,63 @@ def _condition(w: WhereClause, ctx: _Ctx) -> Condition | None:
|
|
|
423
462
|
return None
|
|
424
463
|
|
|
425
464
|
|
|
465
|
+
_NAMES_REASON = "names are matched locally (use the id to filter on Affinity's side)"
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def _valid_ids(value: list[Any]) -> list[int] | str:
|
|
469
|
+
"""The deduplicated record ids in ``value`` (order kept), or the reason they stay local:
|
|
470
|
+
any value that isn't id-shaped (a name) first, then any id outside ``1..ID_MAX``."""
|
|
471
|
+
ids = [_as_entity_id(v) for v in value]
|
|
472
|
+
if any(i is None for i in ids):
|
|
473
|
+
return _NAMES_REASON
|
|
474
|
+
valid = [i for i in ids if i is not None]
|
|
475
|
+
if any(not 1 <= i <= ID_MAX for i in valid):
|
|
476
|
+
return "not a valid record id"
|
|
477
|
+
return list(dict.fromkeys(valid))
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _reference_operator(op: str, value: Any, multi: bool) -> str | None:
|
|
481
|
+
"""The server operator for a person or company condition, or ``None`` when none answers it
|
|
482
|
+
(locally ``in`` / ``has_any`` / ``has_all`` on a single field or with a scalar are False,
|
|
483
|
+
so pushing them would make the filter complete and return nothing)."""
|
|
484
|
+
as_list = isinstance(value, list)
|
|
485
|
+
if multi:
|
|
486
|
+
if (op in ("in", "has_any") and as_list) or (op == "eq" and not as_list):
|
|
487
|
+
return "has-any-of"
|
|
488
|
+
if op in ("has_all", "eq") and as_list:
|
|
489
|
+
return "has-all-of"
|
|
490
|
+
return None
|
|
491
|
+
if (op == "eq" and not as_list) or (op == "in" and as_list):
|
|
492
|
+
return "is-any-of"
|
|
493
|
+
return None
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def _reference(w: WhereClause, meta: FieldMetadata, vt: str, ctx: _Ctx) -> Condition | None:
|
|
497
|
+
"""Record ids on a person or company field: the server matches the id, the local filter
|
|
498
|
+
(which runs afterwards on every record) matches the id too (a number is an id only)."""
|
|
499
|
+
op, value = w.op or "", w.value
|
|
500
|
+
if meta.type == "enriched":
|
|
501
|
+
# Enriched values were never checked with these mappings, and search reads them
|
|
502
|
+
# differently from the entries API
|
|
503
|
+
ctx.local.append(f"{_describe(w)}: Affinity enriched fields stay local")
|
|
504
|
+
return None
|
|
505
|
+
server_op = None if value is None else _reference_operator(op, value, vt.endswith("-multi"))
|
|
506
|
+
if server_op is None:
|
|
507
|
+
ctx.local.append(f"{_describe(w)}: no server mapping for {vt} {op}")
|
|
508
|
+
return None
|
|
509
|
+
if _refused(w, meta, vt, server_op, ctx):
|
|
510
|
+
return None
|
|
511
|
+
items = value if isinstance(value, list) else [value]
|
|
512
|
+
if any(item is None for item in items):
|
|
513
|
+
ctx.local.append(f"{_describe(w)}: no server mapping for {vt} {op}")
|
|
514
|
+
return None
|
|
515
|
+
ids = _valid_ids(items)
|
|
516
|
+
if isinstance(ids, str):
|
|
517
|
+
ctx.local.append(f"{_describe(w)}: {ids}")
|
|
518
|
+
return None
|
|
519
|
+
return _emit(w, meta, vt, server_op, ids, ctx)
|
|
520
|
+
|
|
521
|
+
|
|
426
522
|
def _dropdown(w: WhereClause, meta: FieldMetadata, vt: str, ctx: _Ctx) -> Condition | None:
|
|
427
523
|
"""Locally a dropdown value is the option's text, so map the text test onto option ids."""
|
|
428
524
|
op, value = w.op, w.value
|
|
@@ -29,7 +29,12 @@ from ..entity_search import COMPANY_KEYS, filtered_ls
|
|
|
29
29
|
from ..errors import CLIError
|
|
30
30
|
from ..list_search import is_filter_cursor
|
|
31
31
|
from ..mcp_limits import apply_mcp_limits
|
|
32
|
-
from ..options import
|
|
32
|
+
from ..options import (
|
|
33
|
+
csv_output_options,
|
|
34
|
+
csv_suboption_callback,
|
|
35
|
+
join_filters_callback,
|
|
36
|
+
output_options,
|
|
37
|
+
)
|
|
33
38
|
from ..progress import ProgressManager, ProgressSettings
|
|
34
39
|
from ..resolve import get_company_fields, resolve_list_selector
|
|
35
40
|
from ..resolvers import ResolvedEntity
|
|
@@ -330,9 +335,11 @@ def _parse_field_types(values: tuple[str, ...]) -> list[FieldType] | None:
|
|
|
330
335
|
"--filter",
|
|
331
336
|
"filter_expr",
|
|
332
337
|
type=str,
|
|
333
|
-
|
|
338
|
+
multiple=True,
|
|
339
|
+
callback=join_filters_callback,
|
|
334
340
|
help="Filter on company fields, applied by Affinity's search: 'field op value'. Ops: = != "
|
|
335
|
-
"=~ =^ =$ > < >= <= starts_word. E.g., 'Stage = \"Seed\"'. Name search: --query."
|
|
341
|
+
"=~ =^ =$ > < >= <= starts_word. E.g., 'Stage = \"Seed\"'. Name search: --query. "
|
|
342
|
+
"Repeatable: repeated values are ANDed.",
|
|
336
343
|
)
|
|
337
344
|
@click.option(
|
|
338
345
|
"--query",
|
|
@@ -17,14 +17,15 @@ from affinity.exceptions import (
|
|
|
17
17
|
AuthorizationError,
|
|
18
18
|
ClientSideFilterWarning,
|
|
19
19
|
NotFoundError,
|
|
20
|
+
UnsupportedOperationError,
|
|
20
21
|
)
|
|
21
22
|
from affinity.exceptions import ValidationError as SDKValidationError
|
|
22
23
|
from affinity.filters import FilterExpression
|
|
23
24
|
from affinity.filters import parse as parse_filter
|
|
24
25
|
from affinity.models.entities import FieldMetadata, ListCreate, ListEntryWithEntity
|
|
25
|
-
from affinity.models.pagination import FilterStats
|
|
26
|
+
from affinity.models.pagination import FilterStats, PaginatedResponse
|
|
26
27
|
from affinity.models.types import InteractionType, ListType
|
|
27
|
-
from affinity.services.lists import _entry_to_filter_dict
|
|
28
|
+
from affinity.services.lists import ListEntryService, _entry_to_filter_dict
|
|
28
29
|
from affinity.types import (
|
|
29
30
|
AnyFieldId,
|
|
30
31
|
CompanyId,
|
|
@@ -44,7 +45,12 @@ from ..decorators import category, destructive
|
|
|
44
45
|
from ..errors import CLIError
|
|
45
46
|
from ..list_search import ListSearch, decode_cursor, encode_cursor, plan_list_search
|
|
46
47
|
from ..mcp_limits import apply_mcp_limits
|
|
47
|
-
from ..options import
|
|
48
|
+
from ..options import (
|
|
49
|
+
csv_output_options,
|
|
50
|
+
csv_suboption_callback,
|
|
51
|
+
join_filters_callback,
|
|
52
|
+
output_options,
|
|
53
|
+
)
|
|
48
54
|
from ..render import format_duration
|
|
49
55
|
from ..resolve import (
|
|
50
56
|
list_all_saved_views,
|
|
@@ -452,9 +458,10 @@ ExpandOnError = Literal["raise", "skip"]
|
|
|
452
458
|
"--filter",
|
|
453
459
|
"filter_expr",
|
|
454
460
|
type=str,
|
|
455
|
-
|
|
461
|
+
multiple=True,
|
|
462
|
+
callback=join_filters_callback,
|
|
456
463
|
help="Filter (field op value): Affinity's search applies what it can, the rest is checked "
|
|
457
|
-
'locally. Quote multi-word: Status="Intro Meeting".',
|
|
464
|
+
'locally. Quote multi-word: Status="Intro Meeting". Repeatable: repeated values are ANDed.',
|
|
458
465
|
)
|
|
459
466
|
@click.option(
|
|
460
467
|
"--page-size",
|
|
@@ -570,8 +577,10 @@ ExpandOnError = Literal["raise", "skip"]
|
|
|
570
577
|
"--expand-filter",
|
|
571
578
|
"expand_filter",
|
|
572
579
|
type=str,
|
|
573
|
-
|
|
574
|
-
|
|
580
|
+
multiple=True,
|
|
581
|
+
callback=join_filters_callback,
|
|
582
|
+
help="Filter expanded entities (e.g., 'field=value' or 'field!=value'). "
|
|
583
|
+
"Repeatable: repeated values are ANDed.",
|
|
575
584
|
)
|
|
576
585
|
@click.option(
|
|
577
586
|
"--expand-opportunities-list",
|
|
@@ -1141,6 +1150,33 @@ def list_export(
|
|
|
1141
1150
|
api_called=True,
|
|
1142
1151
|
)
|
|
1143
1152
|
|
|
1153
|
+
# Open Affinity's search here, before any output: a refusal must not surface halfway
|
|
1154
|
+
# through a CSV (its header is already written) or leave a silent first page.
|
|
1155
|
+
search_body: dict[str, Any] | None = list_search.body if list_search else None
|
|
1156
|
+
opened_page: PaginatedResponse[ListEntryWithEntity] | None = None
|
|
1157
|
+
if search_body is not None and filter_expr and not saved_view and cursor is None:
|
|
1158
|
+
try:
|
|
1159
|
+
opened_page = _open_search(
|
|
1160
|
+
client.lists.entries(list_id),
|
|
1161
|
+
search_body,
|
|
1162
|
+
list(dict.fromkeys([*selected_field_ids, *filter_field_ids])),
|
|
1163
|
+
page_size,
|
|
1164
|
+
)
|
|
1165
|
+
except (
|
|
1166
|
+
AuthorizationError,
|
|
1167
|
+
NotFoundError,
|
|
1168
|
+
SDKValidationError,
|
|
1169
|
+
UnsupportedOperationError,
|
|
1170
|
+
) as e:
|
|
1171
|
+
if not (all_pages or max_results is not None or first_page_only):
|
|
1172
|
+
raise _filter_scope_error(
|
|
1173
|
+
filter_expr, list_search.local if list_search else [], reason=str(e)
|
|
1174
|
+
) from e
|
|
1175
|
+
warnings.append(f"Affinity's search refused the filter, filtering locally: {e}")
|
|
1176
|
+
if server_filter is not None:
|
|
1177
|
+
server_filter["fallback"] = e.message
|
|
1178
|
+
search_body = None
|
|
1179
|
+
|
|
1144
1180
|
# Build expand field data structures from parsed_expand_fields
|
|
1145
1181
|
# - expand_field_ids: list of field IDs for API calls
|
|
1146
1182
|
# - field_id_to_display: dict mapping field ID (str) -> display name (original spec)
|
|
@@ -1330,7 +1366,8 @@ def list_export(
|
|
|
1330
1366
|
state=csv_iter_state,
|
|
1331
1367
|
cache=cache,
|
|
1332
1368
|
filter_progress_callback=filter_callback,
|
|
1333
|
-
search=
|
|
1369
|
+
search=search_body,
|
|
1370
|
+
opened_page=opened_page,
|
|
1334
1371
|
filter_field_ids=filter_field_ids,
|
|
1335
1372
|
):
|
|
1336
1373
|
next_cursor = page_next_cursor
|
|
@@ -1656,7 +1693,6 @@ def list_export(
|
|
|
1656
1693
|
# only reach the JSON envelope, which CSV never builds.
|
|
1657
1694
|
for msg in [
|
|
1658
1695
|
*warnings,
|
|
1659
|
-
*csv_iter_state.get("warnings", []),
|
|
1660
1696
|
*truncation_warnings(
|
|
1661
1697
|
csv_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
|
|
1662
1698
|
),
|
|
@@ -1768,7 +1804,8 @@ def list_export(
|
|
|
1768
1804
|
state=table_iter_state,
|
|
1769
1805
|
cache=cache,
|
|
1770
1806
|
filter_progress_callback=json_filter_callback,
|
|
1771
|
-
search=
|
|
1807
|
+
search=search_body,
|
|
1808
|
+
opened_page=opened_page,
|
|
1772
1809
|
filter_field_ids=filter_field_ids,
|
|
1773
1810
|
):
|
|
1774
1811
|
next_cursor = page_next_cursor
|
|
@@ -1911,9 +1948,6 @@ def list_export(
|
|
|
1911
1948
|
warnings.append("Results limited by --max-results. Use --all to fetch all results.")
|
|
1912
1949
|
from ..field_utils import truncation_warnings
|
|
1913
1950
|
|
|
1914
|
-
warnings.extend(table_iter_state.get("warnings", []))
|
|
1915
|
-
if server_filter is not None and table_iter_state.get("searchFallback"):
|
|
1916
|
-
server_filter["fallback"] = table_iter_state["searchFallback"]
|
|
1917
1951
|
warnings.extend(
|
|
1918
1952
|
truncation_warnings(
|
|
1919
1953
|
table_iter_state.get("truncatedFields", []), filtered=bool(filter_expr)
|
|
@@ -2107,6 +2141,7 @@ def _iterate_list_entries(
|
|
|
2107
2141
|
cache: Any = None,
|
|
2108
2142
|
filter_progress_callback: Callable[[FilterStats], None] | None = None,
|
|
2109
2143
|
search: dict[str, Any] | None = None,
|
|
2144
|
+
opened_page: PaginatedResponse[ListEntryWithEntity] | None = None,
|
|
2110
2145
|
filter_field_ids: list[str] | None = None,
|
|
2111
2146
|
) -> Any:
|
|
2112
2147
|
"""
|
|
@@ -2188,38 +2223,27 @@ def _iterate_list_entries(
|
|
|
2188
2223
|
else None
|
|
2189
2224
|
)
|
|
2190
2225
|
if decoded is not None or (search is not None and filter_expr):
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
first = entries.find_body(body, cursor=decoded.url)
|
|
2196
|
-
else:
|
|
2197
|
-
assert search is not None and filter_expr
|
|
2198
|
-
body, local_filter = search, parse_filter(filter_expr)
|
|
2199
|
-
first = entries.find_body(body, field_ids=fetch_ids, limit=page_size)
|
|
2200
|
-
except (AuthorizationError, NotFoundError, SDKValidationError) as e:
|
|
2201
|
-
if decoded is not None:
|
|
2202
|
-
raise
|
|
2203
|
-
if state is not None:
|
|
2204
|
-
state.setdefault("warnings", []).append(
|
|
2205
|
-
f"Affinity's search refused the filter, filtering locally: {e}"
|
|
2206
|
-
)
|
|
2207
|
-
state["searchFallback"] = getattr(e, "message", None) or str(e)
|
|
2226
|
+
if decoded is not None:
|
|
2227
|
+
assert decoded.body is not None
|
|
2228
|
+
body, local_filter = decoded.body, decoded.filter
|
|
2229
|
+
first = entries.find_body(body, cursor=decoded.url)
|
|
2208
2230
|
else:
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2231
|
+
assert search is not None and filter_expr and opened_page is not None
|
|
2232
|
+
body, local_filter, first = search, parse_filter(filter_expr), opened_page
|
|
2233
|
+
yield from _search_rows(
|
|
2234
|
+
entries,
|
|
2235
|
+
first,
|
|
2236
|
+
body=body,
|
|
2237
|
+
local_filter=local_filter,
|
|
2238
|
+
selected_field_ids=selected_field_ids,
|
|
2239
|
+
field_by_id=field_by_id,
|
|
2240
|
+
key_mode=key_mode,
|
|
2241
|
+
max_results=max_results,
|
|
2242
|
+
all_pages=all_pages,
|
|
2243
|
+
state=state,
|
|
2244
|
+
filter_progress_callback=filter_progress_callback,
|
|
2245
|
+
)
|
|
2246
|
+
return
|
|
2223
2247
|
|
|
2224
2248
|
pages = (
|
|
2225
2249
|
entries.pages(cursor=cursor)
|
|
@@ -2292,17 +2316,39 @@ def _filter_names_list_fields(filter_expr: str) -> bool:
|
|
|
2292
2316
|
return False
|
|
2293
2317
|
|
|
2294
2318
|
|
|
2295
|
-
def
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2319
|
+
def _open_search(
|
|
2320
|
+
entries: ListEntryService,
|
|
2321
|
+
body: dict[str, Any],
|
|
2322
|
+
field_ids: list[str],
|
|
2323
|
+
page_size: int,
|
|
2324
|
+
) -> PaginatedResponse[ListEntryWithEntity]:
|
|
2325
|
+
"""First page of Affinity's list entry search (raises when Affinity refuses the filter)."""
|
|
2326
|
+
return entries.find_body(body, field_ids=field_ids, limit=page_size)
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
def _filter_scope_error(filter_expr: str, local: list[str], reason: str | None = None) -> CLIError:
|
|
2330
|
+
scope_flags = (
|
|
2331
|
+
"Add --all to scan everything, --max-results N to cap, or --first-page-only to opt in."
|
|
2305
2332
|
)
|
|
2333
|
+
if reason is None:
|
|
2334
|
+
message = (
|
|
2335
|
+
"Part of this --filter runs locally on fetched pages, so without a scope flag the "
|
|
2336
|
+
f"export would silently return only first-page matches. {scope_flags}"
|
|
2337
|
+
)
|
|
2338
|
+
hint = (
|
|
2339
|
+
"details.local names the conditions Affinity's search can't apply; --saved-view "
|
|
2340
|
+
"filters large lists on Affinity's side."
|
|
2341
|
+
)
|
|
2342
|
+
details: dict[str, Any] = {"rejected_filter": str(filter_expr), "local": local}
|
|
2343
|
+
else:
|
|
2344
|
+
message = (
|
|
2345
|
+
f"Affinity's search refused this --filter ({reason}), so it would run locally on "
|
|
2346
|
+
"fetched pages, and without a scope flag the export would silently return only "
|
|
2347
|
+
f"first-page matches. {scope_flags}"
|
|
2348
|
+
)
|
|
2349
|
+
hint = "Affinity refused the search; add --all or --max-results to filter locally."
|
|
2350
|
+
details = {"rejected_filter": str(filter_expr), "local": local, "refused": reason}
|
|
2351
|
+
return CLIError(message, exit_code=2, error_type="usage_error", hint=hint, details=details)
|
|
2306
2352
|
|
|
2307
2353
|
|
|
2308
2354
|
def _search_rows(
|
|
@@ -27,7 +27,12 @@ from ..entity_search import PERSON_KEYS, filtered_ls
|
|
|
27
27
|
from ..errors import CLIError
|
|
28
28
|
from ..list_search import is_filter_cursor
|
|
29
29
|
from ..mcp_limits import apply_mcp_limits
|
|
30
|
-
from ..options import
|
|
30
|
+
from ..options import (
|
|
31
|
+
csv_output_options,
|
|
32
|
+
csv_suboption_callback,
|
|
33
|
+
join_filters_callback,
|
|
34
|
+
output_options,
|
|
35
|
+
)
|
|
31
36
|
from ..progress import ProgressManager, ProgressSettings
|
|
32
37
|
from ..resolve import get_person_fields, resolve_list_selector
|
|
33
38
|
from ..resolvers import ResolvedEntity
|
|
@@ -207,9 +212,11 @@ def _parse_field_types(values: tuple[str, ...]) -> list[FieldType] | None:
|
|
|
207
212
|
"--filter",
|
|
208
213
|
"filter_expr",
|
|
209
214
|
type=str,
|
|
210
|
-
|
|
215
|
+
multiple=True,
|
|
216
|
+
callback=join_filters_callback,
|
|
211
217
|
help="Filter on person fields, applied by Affinity's search: 'field op value'. Ops: = != "
|
|
212
|
-
"=~ =^ =$ > < >= <= starts_word. E.g., 'Deals > 5'. Name/email search: --query."
|
|
218
|
+
"=~ =^ =$ > < >= <= starts_word. E.g., 'Deals > 5'. Name/email search: --query. "
|
|
219
|
+
"Repeatable: repeated values are ANDed.",
|
|
213
220
|
)
|
|
214
221
|
@click.option(
|
|
215
222
|
"--query",
|
|
@@ -21,7 +21,7 @@ from affinity.filters import FilterExpression
|
|
|
21
21
|
from affinity.services._search import SEARCH_INCLUDES
|
|
22
22
|
|
|
23
23
|
from .query.models import WhereClause
|
|
24
|
-
from .query.pushdown import fields_index, split_where
|
|
24
|
+
from .query.pushdown import ENTITY_VERIFIED, fields_index, split_where
|
|
25
25
|
|
|
26
26
|
# Record attributes (not fields) a company or person filter can test.
|
|
27
27
|
COMPANY_KEYS = frozenset({"id", "name", "domain", "domains"})
|
|
@@ -57,7 +57,7 @@ def plan_entity_search(service: Any, where: WhereClause) -> EntitySearch:
|
|
|
57
57
|
options[key] = list(service.get_field_dropdown_options(meta.id))
|
|
58
58
|
return options[key]
|
|
59
59
|
|
|
60
|
-
split = split_where(where, fields, options_for, enriched="as-is")
|
|
60
|
+
split = split_where(where, fields, options_for, verified=ENTITY_VERIFIED, enriched="as-is")
|
|
61
61
|
index = fields_index(fields)
|
|
62
62
|
field_ids = sorted(
|
|
63
63
|
{
|
|
@@ -94,7 +94,8 @@ def _paths(where: WhereClause) -> set[str]:
|
|
|
94
94
|
|
|
95
95
|
def entity_filter_dict(entity: Any) -> dict[str, Any]:
|
|
96
96
|
"""What a ``--filter`` on companies or persons sees: field values by name (dropdowns as
|
|
97
|
-
text, persons and companies as names) plus the
|
|
97
|
+
text, persons and companies as names; a number in a filter matches their id) plus the
|
|
98
|
+
record's own attributes."""
|
|
98
99
|
result: dict[str, Any] = {}
|
|
99
100
|
by_id: dict[str, Any] = {}
|
|
100
101
|
for item in getattr(entity, "fields_raw", None) or []:
|
|
@@ -4,6 +4,8 @@ import functools
|
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from typing import Any, TypeVar, cast
|
|
6
6
|
|
|
7
|
+
from affinity.filters import parse
|
|
8
|
+
|
|
7
9
|
from .click_compat import click
|
|
8
10
|
from .context import CLIContext, OutputFormat
|
|
9
11
|
from .errors import CLIError
|
|
@@ -143,6 +145,28 @@ def _emit_validation_error(ctx: CLIContext, err: CLIError) -> None:
|
|
|
143
145
|
sys.stderr.write(f"Hint: {err.hint}\n")
|
|
144
146
|
|
|
145
147
|
|
|
148
|
+
def join_filters_callback(
|
|
149
|
+
_ctx: click.Context, _param: click.Parameter, value: tuple[str, ...]
|
|
150
|
+
) -> str | None:
|
|
151
|
+
"""Callback for a repeatable filter option (--filter, --expand-filter): AND the values.
|
|
152
|
+
|
|
153
|
+
One value is passed on unchanged. Repeated values are each parsed on their own first, so a
|
|
154
|
+
value can't close the parentheses it is wrapped in, and its error names it.
|
|
155
|
+
"""
|
|
156
|
+
if not value:
|
|
157
|
+
return None
|
|
158
|
+
if len(value) == 1:
|
|
159
|
+
return value[0]
|
|
160
|
+
for i, text in enumerate(value, 1):
|
|
161
|
+
if not text.strip():
|
|
162
|
+
raise click.BadParameter(f"value {i} is empty; each repeated value needs an expression")
|
|
163
|
+
try:
|
|
164
|
+
parse(text)
|
|
165
|
+
except ValueError as e:
|
|
166
|
+
raise click.BadParameter(f"value {i} ({text!r}): {e}") from e
|
|
167
|
+
return " & ".join(f"({text})" for text in value)
|
|
168
|
+
|
|
169
|
+
|
|
146
170
|
def csv_suboption_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
|
|
147
171
|
"""Callback for CSV-related sub-options (--csv-bom, --csv-header, --csv-mode).
|
|
148
172
|
|