affinity-sdk 0.9.9__tar.gz → 0.9.14__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-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/ci.yml +10 -5
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/release.yml +2 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.gitignore +2 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.pre-commit-config.yaml +7 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/CHANGELOG.md +88 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/PKG-INFO +3 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/README.md +2 -0
- affinity_sdk-0.9.14/affinity/cli/__main__.py +6 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/_entity_files_dump.py +2 -2
- affinity_sdk-0.9.14/affinity/cli/commands/_v1_parsing.py +186 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/company_cmds.py +32 -8
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/interaction_cmds.py +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/list_cmds.py +253 -17
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/note_cmds.py +10 -5
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/opportunity_cmds.py +6 -12
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/person_cmds.py +50 -10
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/query_cmd.py +59 -16
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/reminder_cmds.py +75 -17
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/task_cmds.py +22 -3
- affinity_sdk-0.9.14/affinity/cli/constants.py +16 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/context.py +1 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/formatters.py +108 -0
- affinity_sdk-0.9.14/affinity/cli/interaction_utils.py +580 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/aggregates.py +12 -4
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/executor.py +1030 -69
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/filters.py +108 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/models.py +114 -2
- affinity_sdk-0.9.14/affinity/cli/query/output.py +1104 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/parser.py +46 -6
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/planner.py +190 -18
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/schema.py +105 -3
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/resolve.py +55 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/clients/http.py +2 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/entities.py +14 -4
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/pagination.py +55 -14
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/types.py +19 -8
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/companies.py +384 -50
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/lists.py +155 -35
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/opportunities.py +153 -60
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/persons.py +456 -44
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/v1_only.py +275 -19
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/cli/commands.md +44 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/cli/index.md +10 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/cli/scripting.md +85 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/api-versions-and-routing.md +4 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/errors-and-retries.md +55 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/pagination.md +37 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/performance.md +43 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/query-command.md +106 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/query-language.md +169 -5
- affinity_sdk-0.9.14/docs/public/reference/services/companies.md +47 -0
- affinity_sdk-0.9.14/docs/public/reference/services/persons.md +42 -0
- affinity_sdk-0.9.14/docs/public/troubleshooting.md +58 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/plugin.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/skills/affinity-mcp-workflows/SKILL.md +48 -23
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/skills/query-language/SKILL.md +177 -13
- affinity_sdk-0.9.9/mcp/.registry/commands.json → affinity_sdk-0.9.14/mcp/.registry/commands.generated.json +509 -310
- affinity_sdk-0.9.14/mcp/.registry/mcp-commands.json +362 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.registry/prompts.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.registry/resource-templates.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.registry/resources.json +2 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/CHANGELOG.md +79 -9
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/COMPATIBILITY +8 -2
- affinity_sdk-0.9.14/mcp/VERSION +1 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/lib/cli-gateway.sh +38 -25
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/lib/common.sh +3 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/mcp-bash.lock +2 -2
- affinity_sdk-0.9.14/mcp/mcpb.conf +49 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/data-model/data-model.md +54 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/server.d/env.sh +28 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/server.d/health-checks.sh +3 -3
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/server.d/server.meta.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/test/run.sh +46 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/discover-commands/tool.sh +25 -3
- affinity_sdk-0.9.14/mcp/tools/execute-read-command/tool.meta.json +36 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/execute-read-command/tool.sh +14 -12
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/execute-write-command/tool.meta.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/execute-write-command/tool.sh +23 -25
- affinity_sdk-0.9.14/mcp/tools/query/tool.meta.json +104 -0
- affinity_sdk-0.9.14/mcp/tools/query/tool.sh +183 -0
- affinity_sdk-0.9.14/mcp/user-config.json +35 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mkdocs.yml +2 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/affinity-sdk/.claude-plugin/plugin.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/xaffinity-cli/.claude-plugin/plugin.json +1 -1
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/pyproject.toml +3 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/cli/test_formatters.py +191 -0
- affinity_sdk-0.9.14/tests/cli/test_query_list_entry_relationships.py +643 -0
- affinity_sdk-0.9.14/tests/cli/test_query_list_export_parity.py +319 -0
- affinity_sdk-0.9.14/tests/cli/test_query_output_flattening.py +668 -0
- affinity_sdk-0.9.14/tests/cli/test_query_output_truncation.py +685 -0
- affinity_sdk-0.9.14/tests/cli/test_query_unreplied_emails.py +251 -0
- affinity_sdk-0.9.14/tests/integration/README.md +186 -0
- affinity_sdk-0.9.14/tests/integration/conftest.py +122 -0
- affinity_sdk-0.9.14/tests/integration/setup_query_parity_data.py +414 -0
- affinity_sdk-0.9.14/tests/integration/test_cli_writes.py +594 -0
- affinity_sdk-0.9.14/tests/integration/test_query_parity_integration.py +1124 -0
- affinity_sdk-0.9.14/tests/integration/test_sdk_reads.py +470 -0
- affinity_sdk-0.9.14/tests/integration/test_sdk_writes.py +1767 -0
- affinity_sdk-0.9.14/tests/integration/test_sdk_writes_runner.py +225 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_company_get.py +21 -18
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_csv_export.py +33 -14
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_entity_files_dump.py +1 -0
- affinity_sdk-0.9.14/tests/test_cli_get_interaction_dates.py +262 -0
- affinity_sdk-0.9.14/tests/test_cli_interaction_utils.py +588 -0
- affinity_sdk-0.9.14/tests/test_cli_list_expand_interactions.py +332 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_opportunity_cmds.py +50 -39
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_aggregates.py +26 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_executor.py +506 -1
- affinity_sdk-0.9.14/tests/test_cli_query_expand_interactions.py +1042 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_filters.py +262 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_integration.py +153 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_planner.py +408 -0
- affinity_sdk-0.9.14/tests/test_cli_unreplied_email.py +244 -0
- affinity_sdk-0.9.14/tests/test_cli_v1_parsing.py +195 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_field_value_type.py +3 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_models.py +5 -2
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_requirements_additional.py +2 -2
- affinity_sdk-0.9.14/tests/test_sdk_interaction_dates.py +600 -0
- affinity_sdk-0.9.14/tests/test_service_get_parameter_combinations.py +339 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_lists_additional_coverage.py +10 -3
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_opportunities_additional_coverage.py +82 -16
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_persons_companies_additional_coverage.py +476 -52
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_small_modules_coverage.py +54 -4
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_v1_only_services_more_coverage.py +1 -1
- affinity_sdk-0.9.14/tools/generate_mcp_command_registry.py +239 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/sync_mcp_registry.py +2 -2
- affinity_sdk-0.9.9/affinity/cli/commands/_v1_parsing.py +0 -77
- affinity_sdk-0.9.9/affinity/cli/query/output.py +0 -339
- affinity_sdk-0.9.9/docs/public/reference/services/companies.md +0 -10
- affinity_sdk-0.9.9/docs/public/reference/services/persons.md +0 -5
- affinity_sdk-0.9.9/docs/public/troubleshooting.md +0 -22
- affinity_sdk-0.9.9/mcp/.registry/commands-metadata.json +0 -109
- affinity_sdk-0.9.9/mcp/VERSION +0 -1
- affinity_sdk-0.9.9/mcp/mcpb.conf +0 -24
- affinity_sdk-0.9.9/mcp/tools/execute-read-command/tool.meta.json +0 -42
- affinity_sdk-0.9.9/mcp/tools/query/tool.meta.json +0 -100
- affinity_sdk-0.9.9/mcp/tools/query/tool.sh +0 -106
- affinity_sdk-0.9.9/tools/generate_cli_commands_registry.py +0 -200
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.claude-plugin/marketplace.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.editorconfig +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.env.example +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.gitattributes +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/CODEOWNERS +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/PULL_REQUEST_TEMPLATE/cli_command.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/PULL_REQUEST_TEMPLATE/release.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/dependabot.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/labels.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/pull_request_template.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/docs.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/labels.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/linkcheck.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/openapi-validation.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/plugin-build.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/plugin-release.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/release-detect.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/.github/workflows/version-check.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/CODE_OF_CONDUCT.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/CONTRIBUTING.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/LICENSE +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/SECURITY.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/VERSIONING.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/click_compat.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/_list_entry_fields.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/completion_cmd.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/config_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/entry_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/field_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/relationship_strength_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/resolve_url_cmd.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/session_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/version_cmd.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/commands/whoami_cmd.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/config.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/csv_utils.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/date_utils.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/decorators.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/errors.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/field_utils.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/help_json.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/logging.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/main.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/options.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/paths.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/progress.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/dates.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/exceptions.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/query/progress.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/render.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/resolvers.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/results.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/runner.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/serialization.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/session_cache.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/cli/types.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/client.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/clients/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/clients/pipeline.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/compare.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/downloads.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/exceptions.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/filters.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/hooks.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/inbound_webhooks.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/rate_limit_snapshot.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/models/secondary.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/policies.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/progress.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/py.typed +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/__init__.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/rate_limits.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/services/tasks.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/affinity/types.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/codecov.yml +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/cli-development-guide.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/ai-integrations/index.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/changelog.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/cli-reference.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/examples.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/getting-started.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/glossary.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/authentication.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/claude-code-plugins.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/configuration.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/csv-export.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/datetime-handling.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/debugging-hooks.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/field-types-and-values.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/field-values.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/filtering.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/ids-and-types.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/models.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/opportunity-associations.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/rate-limits.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/sync-vs-async.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/guides/webhooks.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/index.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/mcp/index.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/client.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/exceptions.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/filters.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/models.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/lists.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/opportunities.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/tasks.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/auth.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/field-values.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/fields.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/files.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/interactions.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/notes.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/relationships.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/reminders.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/services/v1/webhooks.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/docs/public/reference/types.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/advanced_usage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/async_lifecycle.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/basic_usage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/filter_builder.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/hooks_debugging.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/list_management.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/resolve_helpers.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/examples/task_polling.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/.gitignore +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/.mcp.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.claude-plugin/xaffinity-mcp.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/.gitignore +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/Makefile +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/README.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/completions/entity-name.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/completions/list-name.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/completions/status-value.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/docs/DEBUGGING.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/docs/internal/debugging-improvements-plan.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/docs/internal/mcp-bash-progress-timeout-feature-request.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/icon.svg +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/lib/cache.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/lib/entity-types.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/lib/field-resolution.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/change-status/change-status.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/change-status/change-status.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/interaction-brief/interaction-brief.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/interaction-brief/interaction-brief.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-call/log-call.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-call/log-call.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-interaction-and-update-workflow/log-interaction-and-update-workflow.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-message/log-message.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/log-message/log-message.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/pipeline-review/pipeline-review.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/pipeline-review/pipeline-review.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/prepare-briefing/prepare-briefing.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/prepare-briefing/prepare-briefing.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/warm-intro/warm-intro.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/prompts/warm-intro/warm-intro.txt +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/providers/xaffinity.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/data-model/data-model.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/field-catalogs/field-catalogs.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/field-catalogs/field-catalogs.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/interaction-enums/interaction-enums.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/interaction-enums/interaction-enums.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/me/me.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/me/me.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/me-person-id/me-person-id.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/me-person-id/me-person-id.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/saved-views/saved-views.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/saved-views/saved-views.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/workflow-config/workflow-config.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/resources/workflow-config/workflow-config.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/scripts/install-framework.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/server.d/policy.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/server.d/requirements.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/test/README.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/test-progress.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/discover-commands/tool.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/get-entity-dossier/tool.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/get-entity-dossier/tool.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/read-xaffinity-resource/tool.meta.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/tools/read-xaffinity-resource/tool.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/xaffinity-mcp-env.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/mcp/xaffinity-mcp.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/affinity-sdk/.claude-plugin/skills/affinity-python-sdk/SKILL.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/xaffinity-cli/.claude-plugin/commands/affinity-help.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/xaffinity-cli/.claude-plugin/hooks/hooks.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/xaffinity-cli/.claude-plugin/hooks/pre-xaffinity.sh +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/plugins/xaffinity-cli/.claude-plugin/skills/xaffinity-cli-usage/SKILL.md +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/cli/test_output_formats_integration.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/conftest.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/field_value_updated.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/list_entry_created.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/organization_created.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/organization_merged.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/person_created.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/fixtures/webhooks/unknown_event.json +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_affinity_client_wrapper_additional_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_async_file_download_streaming.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_column_limiting.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_command_context.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_company_cmds_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_config_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_date_params.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_date_utils.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_datetime_formatting.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_datetime_header_offsets.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_domain_linkification.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_entry_field.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_error_rendering.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_field_history.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_field_value_humanization.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_interaction_date_chunking.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_json_safety.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_list_cmds_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_missing_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_no_network_commands.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_opportunity_cmds_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_pager_logic.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_person_cmds_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_person_get.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_progress_manager.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_cmd.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_dates.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_parser.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_safety.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_query_schema.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_rate_limit_rendering.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_resolve_url_parsing.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_result_summary.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_serialization.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_session_cache.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_types.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_v1_only_cmds.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_cli_write_ops.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_client.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_compare.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_env_helpers.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_exceptions_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_file_download_streaming.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_file_upload_helpers_and_validation.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_filters.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_hooks.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_http_client_additional_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_http_client_remaining_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_inbound_webhooks.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_integration_smoke.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_interactions_and_files_regressions.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_isodatetime.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_list_entry_membership_and_opportunities.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_new_features.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_pagination_iterators.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_public_api.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_raw_pipeline_hook_events.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_companies_coverage_gaps.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_lists_coverage_gaps.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_opportunities_coverage_gaps.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_opportunities_tasks_additional_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_rate_limits_coverage_gaps.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_v1_only_async.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_services_v1_only_coverage_gaps.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_transport_and_readonly_mode.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tests/test_v1_only_services_additional_coverage.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/check_cli_patterns.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/generate_requirements_mapping.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/sync_mcp_version.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/sync_plugin_version.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/tools/validate_openapi_models.py +0 -0
- {affinity_sdk-0.9.9 → affinity_sdk-0.9.14}/uv.lock +0 -0
|
@@ -84,14 +84,19 @@ jobs:
|
|
|
84
84
|
echo "Skipping traceability mapping (docs/internal not present in repo checkout)."
|
|
85
85
|
fi
|
|
86
86
|
|
|
87
|
-
- name:
|
|
87
|
+
- name: MCP commands registry is valid
|
|
88
88
|
run: |
|
|
89
89
|
# Verify registry file exists and is valid JSON with expected structure
|
|
90
90
|
python -c "
|
|
91
91
|
import json
|
|
92
92
|
import sys
|
|
93
|
-
with open('mcp/.registry/commands.json') as f:
|
|
93
|
+
with open('mcp/.registry/commands.generated.json') as f:
|
|
94
94
|
data = json.load(f)
|
|
95
|
+
# Check _generated metadata (auto-generated indicator)
|
|
96
|
+
assert '_generated' in data, 'Missing _generated metadata'
|
|
97
|
+
assert 'generator' in data['_generated'], 'Missing generator in _generated'
|
|
98
|
+
assert 'cliVersion' in data['_generated'], 'Missing cliVersion in _generated'
|
|
99
|
+
# Check commands structure
|
|
95
100
|
assert 'commands' in data, 'Missing commands key'
|
|
96
101
|
assert isinstance(data['commands'], list), 'commands must be a list'
|
|
97
102
|
assert len(data['commands']) > 0, 'commands list is empty'
|
|
@@ -99,11 +104,11 @@ jobs:
|
|
|
99
104
|
assert 'name' in cmd, f'Command missing name: {cmd}'
|
|
100
105
|
assert 'category' in cmd, f'Command {cmd[\"name\"]} missing category'
|
|
101
106
|
assert cmd['category'] in ('read', 'write', 'local'), f'Invalid category for {cmd[\"name\"]}'
|
|
102
|
-
print(f'Registry valid: {len(data[\"commands\"])} commands')
|
|
107
|
+
print(f'Registry valid: {len(data[\"commands\"])} commands (v{data[\"_generated\"][\"cliVersion\"]})')
|
|
103
108
|
"
|
|
104
109
|
# Regenerate registry and verify it matches committed version
|
|
105
|
-
python tools/
|
|
106
|
-
git diff --exit-code mcp/.registry/commands.json
|
|
110
|
+
python tools/generate_mcp_command_registry.py
|
|
111
|
+
git diff --exit-code mcp/.registry/commands.generated.json
|
|
107
112
|
|
|
108
113
|
test-timezone:
|
|
109
114
|
runs-on: ubuntu-latest
|
|
@@ -159,8 +159,8 @@ jobs:
|
|
|
159
159
|
|
|
160
160
|
- name: Verify registry is up to date
|
|
161
161
|
run: |
|
|
162
|
-
python tools/
|
|
163
|
-
git diff --exit-code mcp/.registry/commands.json
|
|
162
|
+
python tools/generate_mcp_command_registry.py
|
|
163
|
+
git diff --exit-code mcp/.registry/commands.generated.json
|
|
164
164
|
|
|
165
165
|
build:
|
|
166
166
|
runs-on: ubuntu-latest
|
|
@@ -66,3 +66,10 @@ repos:
|
|
|
66
66
|
language: python
|
|
67
67
|
files: ^(mcp/VERSION|mcp/\.claude-plugin/plugin\.json|mcp/server\.d/server\.meta\.json)$
|
|
68
68
|
pass_filenames: false
|
|
69
|
+
- id: pytest-pre-push
|
|
70
|
+
name: Run tests before push
|
|
71
|
+
entry: pytest tests/ -x -q --tb=short
|
|
72
|
+
language: system
|
|
73
|
+
pass_filenames: false
|
|
74
|
+
stages: [pre-push]
|
|
75
|
+
always_run: true
|
|
@@ -5,6 +5,85 @@ 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
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## 0.9.14 - 2026-01-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- CLI: Query `select` clause now automatically includes `expand` fields. Previously, using `select` with `expand` would filter out the expansion data (e.g., `interactionDates`, `unrepliedEmails`), requiring users to explicitly list expansions in `select`.
|
|
14
|
+
|
|
15
|
+
## 0.9.13 - 2026-01-19
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- CLI: Query `include` for `listEntries` now supports `persons`, `companies`, `opportunities`, and `interactions`. Fetches related entities based on list entry entity type (e.g., company entries get associated persons).
|
|
19
|
+
- CLI: Query `expand: ["unrepliedEmails"]` now works with `listEntries`. Checks each list entry's underlying entity for unreplied incoming emails.
|
|
20
|
+
- CLI: Query extended include syntax with parameters:
|
|
21
|
+
- `{include: {interactions: {limit: 50, days: 180}}}` - Limit and lookback control
|
|
22
|
+
- `{include: {opportunities: {list: "Pipeline"}}}` - Scope to specific opportunity list
|
|
23
|
+
- `{include: {persons: {where: {...}}}}` - Filter included entities
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- CLI: Query TOON format now correctly flattens `fields.*` and `interactionDates` like markdown and CSV formats do. Previously, TOON was missing the `_apply_explicit_flattening()` call, causing nested fields to be truncated and interaction dates to be missing entirely.
|
|
27
|
+
- CLI: `list export --check-unreplied-emails` now works standalone without requiring `--expand`.
|
|
28
|
+
- CLI: `expand: ["interactionDates"]` now always produces 8 canonical columns regardless of data presence, ensuring consistent schema across all records.
|
|
29
|
+
- SDK: Improved error message when adding wrong entity type to a list (e.g., adding a company to a person list). Now provides clear guidance about list type requirements instead of exposing raw API validation error.
|
|
30
|
+
|
|
31
|
+
### Performance
|
|
32
|
+
- CLI: Query `expand: ["interactionDates"]` is significantly faster with parallel person resolution, bounded concurrent fetches (semaphore=10), and parallelized section resolution. Default concurrency increased from 5 to 15 (tunable via `XAFFINITY_QUERY_CONCURRENCY`).
|
|
33
|
+
|
|
34
|
+
## 0.9.12 - 2026-01-17
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- CLI: Query `listEntries` now normalizes reference field values to display strings:
|
|
38
|
+
- Person fields: `{"firstName": "Jane", "lastName": "Doe"}` → `"Jane Doe"`
|
|
39
|
+
- Company fields: `{"name": "Acme Corp", "id": 123}` → `"Acme Corp"`
|
|
40
|
+
- Multi-person/company fields: Arrays of names instead of raw objects
|
|
41
|
+
- Use `expand` or `include` for full entity data when needed
|
|
42
|
+
- CLI: Query output with explicit `select` on `fields.*` paths now flattens fields to top-level columns in table/CSV/markdown formats. JSON output preserves nested structure.
|
|
43
|
+
|
|
44
|
+
## 0.9.11 - 2026-01-17
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- CLI: Query `include` clause now displays included relationships inline by default. Use `--include-style=separate` for separate tables or `--include-style=ids-only` for raw IDs. JSON output includes full `included` and `included_by_parent` mappings for correlation.
|
|
48
|
+
- CLI: Query `include` extended syntax for custom display fields: `include: {companies: {display: ["name", "domain"]}}`.
|
|
49
|
+
- SDK: `with_interaction_dates` and `with_interaction_persons` parameters for `CompanyService.get()` and `PersonService.get()`. When enabled, routes to V1 API to fetch interaction date summaries (last/next meeting, email dates, team member IDs).
|
|
50
|
+
- CLI: `--expand interactions` option for `list export` command. Adds interaction date summaries to each list entry (last meeting, next meeting, last email, last interaction with daysSince/daysUntil calculations and team member names). Supports both JSON and CSV output formats.
|
|
51
|
+
- CLI: `expand: ["interactionDates"]` support in `query` command. Enriches records with interaction date summaries directly on each record in `result.data`. Works with `persons`, `companies`, and `listEntries` queries.
|
|
52
|
+
- CLI: `--check-unreplied-emails` flag for `list export` command. Detects unreplied incoming emails for each list entry and adds date, daysSince, and subject to output. Use `--unreplied-lookback-days` to configure lookback period (default: 30 days).
|
|
53
|
+
- CLI: `--with-interaction-dates` and `--with-interaction-persons` flags for `company get` and `person get` commands. Fetches interaction date summaries directly in entity get operations.
|
|
54
|
+
- MCP: Query tool `format` parameter now functional (was previously ignored). Supports `toon`, `markdown`, `json`, `jsonl`, `csv`.
|
|
55
|
+
- CLI: `--max-output-bytes` option for `query` command. Enables format-aware truncation for MCP use, returning exit code 100 when truncated.
|
|
56
|
+
- CLI: `format_toon_envelope()` function for TOON output with full envelope (`data[N]{...}:`, `pagination:`, `included_*:` sections).
|
|
57
|
+
- SDK: Batch association methods for PersonService, CompanyService, and OpportunityService:
|
|
58
|
+
- `get_associated_company_ids_batch(person_ids)` / `get_associated_opportunity_ids_batch(person_ids)`
|
|
59
|
+
- `get_associated_person_ids_batch(company_ids)` / `get_associated_opportunity_ids_batch(company_ids)`
|
|
60
|
+
- `get_associated_person_ids_batch(opportunity_ids)` / `get_associated_company_ids_batch(opportunity_ids)`
|
|
61
|
+
- All return `dict[EntityId, list[AssocId]]` with `on_error="raise"|"skip"` parameter.
|
|
62
|
+
- SDK: `retries` parameter on `persons.get()`, `companies.get()`, and `opportunities.get()` methods. Enables automatic retry with exponential backoff on 404 errors to handle V1→V2 eventual consistency after create operations. Default is `retries=0` (fail fast).
|
|
63
|
+
- CLI: Reminder date options now accept relative dates and keywords in addition to ISO-8601:
|
|
64
|
+
- `--due-date`: `+7d`, `+2w`, `+1m`, `+1y`, `today`, `tomorrow`, `yesterday`, `now`
|
|
65
|
+
- `--due-after`, `--due-before`: Same formats for filtering in `reminder ls`
|
|
66
|
+
- Example: `xaffinity reminder create --due-date +7d --type one-time --owner-id 123`
|
|
67
|
+
- CLI: Domain validation for `company create` and `company update` now provides helpful error messages:
|
|
68
|
+
- Detects underscores (RFC 1035 violation) and suggests dash replacement
|
|
69
|
+
- Detects URL prefixes and extracts domain
|
|
70
|
+
- Example: `--domain test_company.com` → "Use 'test-company.com' instead"
|
|
71
|
+
- Docs: V1→V2 eventual consistency guide covering 404 after create and stale data after update scenarios.
|
|
72
|
+
- Tests: Integration test suite for SDK write operations (`tests/integration/`).
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
- SDK: `OpportunityService.get_associated_people()` and `get_associated_companies()` now use V2 batch lookup instead of individual V1 fetches, reducing N+1 API calls (e.g., 50 people now fetched in 2 calls instead of 51).
|
|
76
|
+
- SDK: Query executor `_batch_fetch_by_ids()` now uses V2 batch lookup for persons and companies, improving query performance on relationship includes.
|
|
77
|
+
- CLI: Query `include` clause now fetches relationship IDs in parallel, then batch-fetches full records via V2 API, reducing API calls from N×M to N+1 for deduped lookups.
|
|
78
|
+
|
|
79
|
+
### Changed (Breaking)
|
|
80
|
+
- MCP: Query tool default format changed from `json` to `toon` for better token efficiency (~40% fewer tokens).
|
|
81
|
+
- CLI: TOON query output now includes full envelope structure instead of data-only format. The `data` prefix is added to the array header: `data[N]{fields}:` instead of `[N]{fields}:`.
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- MCP: Query tool now honors the `format` parameter instead of always using JSON output.
|
|
85
|
+
- SDK: `ListEntryService.batch_update_fields()` now uses correct V2 API payload format. Previously failed with "Missing discriminator for property operation" error.
|
|
86
|
+
|
|
8
87
|
## 0.9.9 - 2026-01-14
|
|
9
88
|
|
|
10
89
|
### Added
|
|
@@ -162,7 +241,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
162
241
|
- CLI: `--limit` alias for `--max-results` on all `ls` commands (LLM-friendly).
|
|
163
242
|
- CLI: Option aliases now included in `--help --json` output.
|
|
164
243
|
|
|
165
|
-
## 0.8.
|
|
244
|
+
## 0.8.2 - 2026-01-10
|
|
245
|
+
|
|
246
|
+
_No user-facing changes. Version bump for PyPI release._
|
|
247
|
+
|
|
248
|
+
## 0.8.1 - 2026-01-10
|
|
249
|
+
|
|
250
|
+
_No user-facing changes. Version bump for PyPI release._
|
|
251
|
+
|
|
252
|
+
## 0.8.0 - 2026-01-10
|
|
166
253
|
|
|
167
254
|
### Changed
|
|
168
255
|
- CLI: Renamed `--json` to `--set-json` on `person field`, `company field`, `opportunity field` commands to avoid conflict with global `--json` output flag.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: affinity-sdk
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.14
|
|
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/
|
|
@@ -126,6 +126,8 @@ Optional: install the CLI:
|
|
|
126
126
|
pipx install "affinity-sdk[cli]"
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
The CLI includes a powerful `query` command for structured data extraction with filtering, aggregations, and relationship includes. Output formats include JSON, CSV, markdown, and TOON (token-optimized for LLMs).
|
|
130
|
+
|
|
129
131
|
CLI docs: https://yaniv-golan.github.io/affinity-sdk/latest/cli/
|
|
130
132
|
|
|
131
133
|
### MCP Server
|
|
@@ -69,6 +69,8 @@ Optional: install the CLI:
|
|
|
69
69
|
pipx install "affinity-sdk[cli]"
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
The CLI includes a powerful `query` command for structured data extraction with filtering, aggregations, and relationship includes. Output formats include JSON, CSV, markdown, and TOON (token-optimized for LLMs).
|
|
73
|
+
|
|
72
74
|
CLI docs: https://yaniv-golan.github.io/affinity-sdk/latest/cli/
|
|
73
75
|
|
|
74
76
|
### MCP Server
|
|
@@ -94,9 +94,9 @@ async def dump_entity_files_bundle(
|
|
|
94
94
|
break
|
|
95
95
|
if max_files is not None and produced >= max_files:
|
|
96
96
|
break
|
|
97
|
-
if not resp.
|
|
97
|
+
if not resp.next_cursor:
|
|
98
98
|
break
|
|
99
|
-
token = resp.
|
|
99
|
+
token = resp.next_cursor
|
|
100
100
|
|
|
101
101
|
for _ in range(workers):
|
|
102
102
|
await queue.put(None)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from typing import Any, TypeVar
|
|
7
|
+
|
|
8
|
+
from ..errors import CLIError
|
|
9
|
+
from ..query.dates import is_relative_date, parse_relative_date
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_choice(value: str | None, mapping: Mapping[str, T], *, label: str) -> T | None:
|
|
15
|
+
if value is None:
|
|
16
|
+
return None
|
|
17
|
+
key = value.strip().lower()
|
|
18
|
+
if key in mapping:
|
|
19
|
+
return mapping[key]
|
|
20
|
+
choices = ", ".join(sorted(mapping.keys()))
|
|
21
|
+
raise CLIError(
|
|
22
|
+
f"Unknown {label}: {value}",
|
|
23
|
+
error_type="usage_error",
|
|
24
|
+
exit_code=2,
|
|
25
|
+
hint=f"Choose one of: {choices}.",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def validate_domain(value: str | None, *, label: str = "domain") -> str | None:
|
|
30
|
+
"""
|
|
31
|
+
Validate domain format before API call.
|
|
32
|
+
|
|
33
|
+
Checks for common domain format mistakes that would be rejected by the
|
|
34
|
+
Affinity API with a cryptic error message. Validates against RFC 1035
|
|
35
|
+
constraints and common user errors.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
value: Domain string to validate (or None)
|
|
39
|
+
label: Human-readable label for error messages
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
The validated domain string (unchanged), or None if input was None
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
CLIError: If domain format is invalid
|
|
46
|
+
"""
|
|
47
|
+
if value is None:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
domain = value.strip()
|
|
51
|
+
if not domain:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
# Check for protocol prefix (common mistake)
|
|
55
|
+
if domain.startswith(("http://", "https://")):
|
|
56
|
+
# Extract domain from URL
|
|
57
|
+
clean = domain.split("//", 1)[1].split("/", 1)[0]
|
|
58
|
+
raise CLIError(
|
|
59
|
+
f"Invalid {label}: provide domain only, not URL",
|
|
60
|
+
error_type="usage_error",
|
|
61
|
+
exit_code=2,
|
|
62
|
+
hint=f"Use '{clean}' instead of '{value}'.",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Check for underscores (RFC 1035 violation - most common issue)
|
|
66
|
+
if "_" in domain:
|
|
67
|
+
suggested = domain.replace("_", "-")
|
|
68
|
+
raise CLIError(
|
|
69
|
+
f"Invalid {label}: domains cannot contain underscores",
|
|
70
|
+
error_type="usage_error",
|
|
71
|
+
exit_code=2,
|
|
72
|
+
hint=f"Use '{suggested}' instead of '{domain}'.",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Check for spaces
|
|
76
|
+
if " " in domain:
|
|
77
|
+
raise CLIError(
|
|
78
|
+
f"Invalid {label}: domains cannot contain spaces",
|
|
79
|
+
error_type="usage_error",
|
|
80
|
+
exit_code=2,
|
|
81
|
+
hint="Remove spaces from the domain.",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return domain
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def parse_iso_datetime(value: str, *, label: str) -> datetime:
|
|
88
|
+
"""
|
|
89
|
+
Parse ISO-8601 datetime string to UTC-aware datetime.
|
|
90
|
+
|
|
91
|
+
Timezone handling:
|
|
92
|
+
- Explicit timezone (Z or offset): Respected, converted to UTC
|
|
93
|
+
- Naive string: Interpreted as LOCAL time, converted to UTC
|
|
94
|
+
|
|
95
|
+
This provides intuitive UX for CLI users who think in local time.
|
|
96
|
+
|
|
97
|
+
Examples (assuming user is in EST/UTC-5):
|
|
98
|
+
"2024-01-01" → 2024-01-01T05:00:00Z (midnight EST)
|
|
99
|
+
"2024-01-01T12:00:00" → 2024-01-01T17:00:00Z (noon EST)
|
|
100
|
+
"2024-01-01T12:00:00Z" → 2024-01-01T12:00:00Z (explicit UTC)
|
|
101
|
+
"2024-01-01T12:00:00-05:00" → 2024-01-01T17:00:00Z (explicit EST)
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
UTC-aware datetime object
|
|
105
|
+
"""
|
|
106
|
+
raw = value.strip()
|
|
107
|
+
if raw.endswith("Z"):
|
|
108
|
+
raw = raw[:-1] + "+00:00"
|
|
109
|
+
try:
|
|
110
|
+
dt = datetime.fromisoformat(raw)
|
|
111
|
+
except ValueError as exc:
|
|
112
|
+
raise CLIError(
|
|
113
|
+
f"Invalid {label} datetime: {value}",
|
|
114
|
+
error_type="usage_error",
|
|
115
|
+
exit_code=2,
|
|
116
|
+
hint="Use ISO-8601, e.g. 2024-01-01, 2024-01-01T13:00:00, or 2024-01-01T13:00:00Z.",
|
|
117
|
+
) from exc
|
|
118
|
+
|
|
119
|
+
# Convert to UTC
|
|
120
|
+
if dt.tzinfo is None:
|
|
121
|
+
# Naive datetime = local time
|
|
122
|
+
# astimezone() on naive datetime uses system timezone
|
|
123
|
+
dt = dt.astimezone()
|
|
124
|
+
return dt.astimezone(timezone.utc)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def parse_date_flexible(
|
|
128
|
+
value: str,
|
|
129
|
+
*,
|
|
130
|
+
label: str,
|
|
131
|
+
now: datetime | None = None,
|
|
132
|
+
) -> datetime:
|
|
133
|
+
"""
|
|
134
|
+
Parse date string as either relative or ISO format.
|
|
135
|
+
|
|
136
|
+
Tries relative first (+7d, tomorrow), then ISO-8601.
|
|
137
|
+
Returns UTC-aware datetime.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
value: Date string to parse
|
|
141
|
+
label: Human-readable label for error messages
|
|
142
|
+
now: Reference time for relative dates (default: current UTC)
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
UTC-aware datetime
|
|
146
|
+
|
|
147
|
+
Raises:
|
|
148
|
+
CLIError: If value cannot be parsed as either format
|
|
149
|
+
"""
|
|
150
|
+
# Validate non-empty
|
|
151
|
+
if not value or not value.strip():
|
|
152
|
+
raise CLIError(
|
|
153
|
+
f"Missing {label} date value",
|
|
154
|
+
error_type="usage_error",
|
|
155
|
+
exit_code=2,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Try relative date first
|
|
159
|
+
if is_relative_date(value):
|
|
160
|
+
try:
|
|
161
|
+
return parse_relative_date(value, now=now, use_utc=True)
|
|
162
|
+
except ValueError:
|
|
163
|
+
pass # Shouldn't happen if is_relative_date() returned True
|
|
164
|
+
|
|
165
|
+
# Fall back to ISO parsing, but wrap error with unified hint
|
|
166
|
+
try:
|
|
167
|
+
return parse_iso_datetime(value, label=label)
|
|
168
|
+
except CLIError:
|
|
169
|
+
raise CLIError(
|
|
170
|
+
f"Invalid {label} date: {value}",
|
|
171
|
+
error_type="usage_error",
|
|
172
|
+
exit_code=2,
|
|
173
|
+
hint="Use ISO-8601 (2026-01-01), relative (+7d, +2w), or keyword (today, tomorrow).",
|
|
174
|
+
) from None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def parse_json_value(value: str, *, label: str) -> Any:
|
|
178
|
+
try:
|
|
179
|
+
return json.loads(value)
|
|
180
|
+
except json.JSONDecodeError as exc:
|
|
181
|
+
raise CLIError(
|
|
182
|
+
f"Invalid JSON for {label}.",
|
|
183
|
+
error_type="usage_error",
|
|
184
|
+
exit_code=2,
|
|
185
|
+
hint='Provide a valid JSON literal (e.g. "\\"text\\"", 123, true, {"k": 1}).',
|
|
186
|
+
) from exc
|
|
@@ -32,6 +32,7 @@ from ._list_entry_fields import (
|
|
|
32
32
|
build_list_entry_field_rows,
|
|
33
33
|
filter_list_entry_fields,
|
|
34
34
|
)
|
|
35
|
+
from ._v1_parsing import validate_domain
|
|
35
36
|
from .resolve_url_cmd import _parse_affinity_url
|
|
36
37
|
|
|
37
38
|
|
|
@@ -484,7 +485,7 @@ def company_ls(
|
|
|
484
485
|
page_size=page_size,
|
|
485
486
|
page_token=cursor,
|
|
486
487
|
):
|
|
487
|
-
next_cursor = v1_page.
|
|
488
|
+
next_cursor = v1_page.next_cursor
|
|
488
489
|
prev_cursor = None # V1 doesn't have prev cursor
|
|
489
490
|
|
|
490
491
|
if v1_page.data:
|
|
@@ -526,7 +527,7 @@ def company_ls(
|
|
|
526
527
|
page_size=page_size,
|
|
527
528
|
page_token=cursor,
|
|
528
529
|
):
|
|
529
|
-
next_cursor = search_page.
|
|
530
|
+
next_cursor = search_page.next_cursor
|
|
530
531
|
prev_cursor = None # Search doesn't have prev cursor
|
|
531
532
|
|
|
532
533
|
for idx, company in enumerate(search_page.data):
|
|
@@ -717,7 +718,7 @@ def _resolve_company_by_domain(*, client: Any, domain: str) -> CompanyId:
|
|
|
717
718
|
matches.append(company)
|
|
718
719
|
if len(matches) >= 20:
|
|
719
720
|
break
|
|
720
|
-
if len(matches) >= 20 or not page.
|
|
721
|
+
if len(matches) >= 20 or not page.next_cursor:
|
|
721
722
|
break
|
|
722
723
|
|
|
723
724
|
if not matches:
|
|
@@ -758,7 +759,7 @@ def _resolve_company_by_name(*, client: Any, name: str) -> CompanyId:
|
|
|
758
759
|
matches.append(company)
|
|
759
760
|
if len(matches) >= 20:
|
|
760
761
|
break
|
|
761
|
-
if len(matches) >= 20 or not page.
|
|
762
|
+
if len(matches) >= 20 or not page.next_cursor:
|
|
762
763
|
break
|
|
763
764
|
|
|
764
765
|
if not matches:
|
|
@@ -915,7 +916,7 @@ def company_files_dump(
|
|
|
915
916
|
ctx_modifiers["outDir"] = out_dir
|
|
916
917
|
if overwrite:
|
|
917
918
|
ctx_modifiers["overwrite"] = True
|
|
918
|
-
if concurrency !=
|
|
919
|
+
if concurrency != 3:
|
|
919
920
|
ctx_modifiers["concurrency"] = concurrency
|
|
920
921
|
if page_size != 100:
|
|
921
922
|
ctx_modifiers["pageSize"] = page_size
|
|
@@ -1119,6 +1120,18 @@ def company_files_upload(
|
|
|
1119
1120
|
is_flag=True,
|
|
1120
1121
|
help="Fetch all pages for expansions (still capped by --max-results if set).",
|
|
1121
1122
|
)
|
|
1123
|
+
@click.option(
|
|
1124
|
+
"--with-interaction-dates",
|
|
1125
|
+
"with_interaction_dates",
|
|
1126
|
+
is_flag=True,
|
|
1127
|
+
help="Include interaction date summaries (last/next meeting, email dates).",
|
|
1128
|
+
)
|
|
1129
|
+
@click.option(
|
|
1130
|
+
"--with-interaction-persons",
|
|
1131
|
+
"with_interaction_persons",
|
|
1132
|
+
is_flag=True,
|
|
1133
|
+
help="Include person IDs for each interaction (requires --with-interaction-dates).",
|
|
1134
|
+
)
|
|
1122
1135
|
@output_options
|
|
1123
1136
|
@click.pass_obj
|
|
1124
1137
|
def company_get(
|
|
@@ -1136,6 +1149,8 @@ def company_get(
|
|
|
1136
1149
|
list_entry_fields_scope: ListEntryFieldsScope,
|
|
1137
1150
|
max_results: int | None,
|
|
1138
1151
|
all_pages: bool,
|
|
1152
|
+
with_interaction_dates: bool,
|
|
1153
|
+
with_interaction_persons: bool,
|
|
1139
1154
|
) -> None:
|
|
1140
1155
|
"""
|
|
1141
1156
|
Get a company by id, URL, domain, or name.
|
|
@@ -1359,6 +1374,8 @@ def company_get(
|
|
|
1359
1374
|
company_id,
|
|
1360
1375
|
field_ids=field_ids,
|
|
1361
1376
|
field_types=field_types_param,
|
|
1377
|
+
with_interaction_dates=with_interaction_dates,
|
|
1378
|
+
with_interaction_persons=with_interaction_persons,
|
|
1362
1379
|
)
|
|
1363
1380
|
company_payload = serialize_model_for_cli(company)
|
|
1364
1381
|
fields_raw = getattr(company, "fields_raw", None)
|
|
@@ -1744,11 +1761,13 @@ def company_create(
|
|
|
1744
1761
|
"""Create a company."""
|
|
1745
1762
|
|
|
1746
1763
|
def fn(ctx: CLIContext, warnings: list[str]) -> CommandOutput:
|
|
1764
|
+
validated_domain = validate_domain(domain, label="domain")
|
|
1765
|
+
|
|
1747
1766
|
client = ctx.get_client(warnings=warnings)
|
|
1748
1767
|
created = client.companies.create(
|
|
1749
1768
|
CompanyCreate(
|
|
1750
1769
|
name=name,
|
|
1751
|
-
domain=
|
|
1770
|
+
domain=validated_domain,
|
|
1752
1771
|
person_ids=[PersonId(pid) for pid in person_ids],
|
|
1753
1772
|
)
|
|
1754
1773
|
)
|
|
@@ -1807,12 +1826,14 @@ def company_update(
|
|
|
1807
1826
|
error_type="usage_error",
|
|
1808
1827
|
hint="Use --name, --domain, or --person-id.",
|
|
1809
1828
|
)
|
|
1829
|
+
validated_domain = validate_domain(domain, label="domain")
|
|
1830
|
+
|
|
1810
1831
|
client = ctx.get_client(warnings=warnings)
|
|
1811
1832
|
updated = client.companies.update(
|
|
1812
1833
|
CompanyId(company_id),
|
|
1813
1834
|
CompanyUpdate(
|
|
1814
1835
|
name=name,
|
|
1815
|
-
domain=
|
|
1836
|
+
domain=validated_domain,
|
|
1816
1837
|
person_ids=[PersonId(pid) for pid in person_ids] if person_ids else None,
|
|
1817
1838
|
),
|
|
1818
1839
|
)
|
|
@@ -1883,7 +1904,10 @@ def company_merge(
|
|
|
1883
1904
|
primary_id: int,
|
|
1884
1905
|
duplicate_id: int,
|
|
1885
1906
|
) -> None:
|
|
1886
|
-
"""Merge a duplicate company into a primary
|
|
1907
|
+
"""Merge a duplicate company into a primary (beta).
|
|
1908
|
+
|
|
1909
|
+
Returns a taskUrl for tracking progress. Use 'task wait <url>' to wait for completion.
|
|
1910
|
+
"""
|
|
1887
1911
|
|
|
1888
1912
|
def fn(ctx: CLIContext, warnings: list[str]) -> CommandOutput:
|
|
1889
1913
|
client = ctx.get_client(warnings=warnings)
|