diff --git a/.gitignore b/.gitignore index 7d8bcf8..8a99f51 100644 --- a/.gitignore +++ b/.gitignore @@ -169,4 +169,5 @@ __pycache__ claude.sync config.json claudesync.log -chats \ No newline at end of file +chats +some_value \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index cdb3d19..9084770 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "claudesync" -version = "0.3.9" +version = "0.4.0" authors = [ {name = "Jahziah Wagner", email = "jahziah.wagner+pypi@gmail.com"}, ] diff --git a/src/claudesync/cli/organization.py b/src/claudesync/cli/organization.py index de585d1..5184aa2 100644 --- a/src/claudesync/cli/organization.py +++ b/src/claudesync/cli/organization.py @@ -13,13 +13,15 @@ def organization(): @click.pass_obj @handle_errors def ls(config): - """List all available organizations.""" + """List all available organizations with required capabilities.""" provider = validate_and_get_provider(config, require_org=False) organizations = provider.get_organizations() if not organizations: - click.echo("No organizations found.") + click.echo( + "No organizations with required capabilities (chat and claude_pro) found." + ) else: - click.echo("Available organizations:") + click.echo("Available organizations with required capabilities:") for idx, org in enumerate(organizations, 1): click.echo(f" {idx}. {org['name']} (ID: {org['id']})") @@ -32,9 +34,11 @@ def select(config): provider = validate_and_get_provider(config, require_org=False) organizations = provider.get_organizations() if not organizations: - click.echo("No organizations found.") + click.echo( + "No organizations with required capabilities (chat and claude_pro) found." + ) return - click.echo("Available organizations:") + click.echo("Available organizations with required capabilities:") for idx, org in enumerate(organizations, 1): click.echo(f" {idx}. {org['name']} (ID: {org['id']})") selection = click.prompt("Enter the number of the organization to select", type=int) diff --git a/src/claudesync/providers/base_claude_ai.py b/src/claudesync/providers/base_claude_ai.py index 170b54b..690ab84 100644 --- a/src/claudesync/providers/base_claude_ai.py +++ b/src/claudesync/providers/base_claude_ai.py @@ -33,7 +33,11 @@ def get_organizations(self): response = self._make_request("GET", "/organizations") if not response: raise ProviderError("Unable to retrieve organization information") - return [{"id": org["uuid"], "name": org["name"]} for org in response] + return [ + {"id": org["uuid"], "name": org["name"]} + for org in response + if set(["chat", "claude_pro"]).issubset(set(org.get("capabilities", []))) + ] def get_projects(self, organization_id, include_archived=False): response = self._make_request( diff --git a/tests/cli/test_organization.py b/tests/cli/test_organization.py index 90ba841..96ca54f 100644 --- a/tests/cli/test_organization.py +++ b/tests/cli/test_organization.py @@ -14,8 +14,16 @@ def test_organization_ls(self, mock_validate_and_get_provider): # Mock the provider mock_provider = MagicMock() mock_provider.get_organizations.return_value = [ - {"id": "org1", "name": "Organization 1"}, - {"id": "org2", "name": "Organization 2"}, + { + "id": "org1", + "name": "Organization 1", + "capabilities": ["chat", "claude_pro"], + }, + { + "id": "org2", + "name": "Organization 2", + "capabilities": ["chat", "claude_pro"], + }, ] mock_validate_and_get_provider.return_value = mock_provider @@ -29,7 +37,10 @@ def test_organization_ls(self, mock_validate_and_get_provider): mock_provider.get_organizations.return_value = [] result = self.runner.invoke(cli, ["organization", "ls"]) self.assertEqual(result.exit_code, 0) - self.assertIn("No organizations found.", result.output) + self.assertIn( + "No organizations with required capabilities (chat and claude_pro) found.", + result.output, + ) # Test error handling mock_validate_and_get_provider.side_effect = ConfigurationError( @@ -45,8 +56,16 @@ def test_organization_select(self, mock_prompt, mock_validate_and_get_provider): # Mock the provider mock_provider = MagicMock() mock_provider.get_organizations.return_value = [ - {"id": "org1", "name": "Organization 1"}, - {"id": "org2", "name": "Organization 2"}, + { + "id": "org1", + "name": "Organization 1", + "capabilities": ["chat", "claude_pro"], + }, + { + "id": "org2", + "name": "Organization 2", + "capabilities": ["chat", "claude_pro"], + }, ] mock_validate_and_get_provider.return_value = mock_provider @@ -68,7 +87,10 @@ def test_organization_select(self, mock_prompt, mock_validate_and_get_provider): mock_provider.get_organizations.return_value = [] result = self.runner.invoke(cli, ["organization", "select"]) self.assertEqual(result.exit_code, 0) - self.assertIn("No organizations found.", result.output) + self.assertIn( + "No organizations with required capabilities (chat and claude_pro) found.", + result.output, + ) # Test error handling mock_validate_and_get_provider.side_effect = ProviderError("Provider error") diff --git a/tests/providers/test_base_claude_ai.py b/tests/providers/test_base_claude_ai.py index 8457fc7..7d7412e 100644 --- a/tests/providers/test_base_claude_ai.py +++ b/tests/providers/test_base_claude_ai.py @@ -1,5 +1,7 @@ import unittest from unittest.mock import patch + +from claudesync.exceptions import ProviderError from claudesync.providers.base_claude_ai import BaseClaudeAIProvider @@ -18,13 +20,34 @@ def test_login(self, mock_prompt): @patch.object(BaseClaudeAIProvider, "_make_request") def test_get_organizations(self, mock_make_request): mock_make_request.return_value = [ - {"uuid": "org1", "name": "Org 1"}, - {"uuid": "org2", "name": "Org 2"}, + {"uuid": "org1", "name": "Org 1", "capabilities": ["chat", "claude_pro"]}, + {"uuid": "org2", "name": "Org 2", "capabilities": ["chat"]}, + { + "uuid": "org3", + "name": "Org 3", + "capabilities": ["chat", "claude_pro", "other"], + }, + {"uuid": "org4", "name": "Org 4", "capabilities": ["other"]}, ] result = self.provider.get_organizations() - expected = [{"id": "org1", "name": "Org 1"}, {"id": "org2", "name": "Org 2"}] + expected = [{"id": "org1", "name": "Org 1"}, {"id": "org3", "name": "Org 3"}] self.assertEqual(result, expected) + @patch.object(BaseClaudeAIProvider, "_make_request") + def test_get_organizations_no_valid_orgs(self, mock_make_request): + mock_make_request.return_value = [ + {"uuid": "org1", "name": "Org 1", "capabilities": ["api"]}, + {"uuid": "org2", "name": "Org 2", "capabilities": ["chat"]}, + ] + result = self.provider.get_organizations() + self.assertEqual(result, []) + + @patch.object(BaseClaudeAIProvider, "_make_request") + def test_get_organizations_error(self, mock_make_request): + mock_make_request.return_value = None + with self.assertRaises(ProviderError): + self.provider.get_organizations() + @patch.object(BaseClaudeAIProvider, "_make_request") def test_get_projects(self, mock_make_request): mock_make_request.return_value = [