claudesync 0.2.7__tar.gz → 0.2.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {claudesync-0.2.7 → claudesync-0.2.9}/LICENSE +1 -1
  2. claudesync-0.2.9/PKG-INFO +153 -0
  3. claudesync-0.2.9/README.md +109 -0
  4. {claudesync-0.2.7 → claudesync-0.2.9}/pyproject.toml +17 -4
  5. {claudesync-0.2.7 → claudesync-0.2.9}/setup.py +1 -1
  6. claudesync-0.2.9/src/claudesync/__init__.py +0 -0
  7. claudesync-0.2.9/src/claudesync/cli/__init__.py +3 -0
  8. claudesync-0.2.9/src/claudesync/cli/auth.py +34 -0
  9. claudesync-0.2.9/src/claudesync/cli/main.py +60 -0
  10. claudesync-0.2.9/src/claudesync/cli/organization.py +47 -0
  11. claudesync-0.2.9/src/claudesync/cli/project.py +122 -0
  12. claudesync-0.2.9/src/claudesync/cli/sync.py +120 -0
  13. claudesync-0.2.9/src/claudesync/config_manager.py +30 -0
  14. claudesync-0.2.9/src/claudesync/exceptions.py +10 -0
  15. claudesync-0.2.9/src/claudesync/provider_factory.py +19 -0
  16. claudesync-0.2.9/src/claudesync/providers/__init__.py +0 -0
  17. claudesync-0.2.9/src/claudesync/providers/claude_ai.py +166 -0
  18. claudesync-0.2.9/src/claudesync/utils.py +122 -0
  19. claudesync-0.2.9/src/claudesync.egg-info/PKG-INFO +153 -0
  20. claudesync-0.2.9/src/claudesync.egg-info/SOURCES.txt +29 -0
  21. claudesync-0.2.9/src/claudesync.egg-info/entry_points.txt +2 -0
  22. claudesync-0.2.9/src/claudesync.egg-info/requires.txt +8 -0
  23. claudesync-0.2.9/tests/test_auth.py +29 -0
  24. claudesync-0.2.9/tests/test_main.py +29 -0
  25. claudesync-0.2.9/tests/test_organization.py +81 -0
  26. claudesync-0.2.9/tests/test_project.py +128 -0
  27. claudesync-0.2.9/tests/test_sync.py +147 -0
  28. claudesync-0.2.9/tests/test_utils.py +59 -0
  29. claudesync-0.2.7/PKG-INFO +0 -85
  30. claudesync-0.2.7/README.md +0 -68
  31. claudesync-0.2.7/src/claudesync/__init__.py +0 -7
  32. claudesync-0.2.7/src/claudesync/api_utils.py +0 -94
  33. claudesync-0.2.7/src/claudesync/debounce.py +0 -21
  34. claudesync-0.2.7/src/claudesync/file_handler.py +0 -123
  35. claudesync-0.2.7/src/claudesync/gitignore_utils.py +0 -31
  36. claudesync-0.2.7/src/claudesync/main.py +0 -163
  37. claudesync-0.2.7/src/claudesync/manual_auth.py +0 -77
  38. claudesync-0.2.7/src/claudesync.egg-info/PKG-INFO +0 -85
  39. claudesync-0.2.7/src/claudesync.egg-info/SOURCES.txt +0 -17
  40. claudesync-0.2.7/src/claudesync.egg-info/entry_points.txt +0 -2
  41. claudesync-0.2.7/src/claudesync.egg-info/requires.txt +0 -3
  42. {claudesync-0.2.7 → claudesync-0.2.9}/setup.cfg +0 -0
  43. {claudesync-0.2.7 → claudesync-0.2.9}/src/claudesync.egg-info/dependency_links.txt +0 -0
  44. {claudesync-0.2.7 → claudesync-0.2.9}/src/claudesync.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 jahwag
3
+ Copyright (c) 2024 Jahziah Wagner
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.1
2
+ Name: claudesync
3
+ Version: 0.2.9
4
+ Summary: A tool to synchronize local files with Claude.ai projects
5
+ Author-email: Jahziah Wagner <jahziah.wagner+pypi@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Jahziah Wagner
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/jahwag/claudesync
29
+ Project-URL: Bug Tracker, https://github.com/jahwag/claudesync/issues
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Operating System :: OS Independent
33
+ Requires-Python: >=3.7
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: Click
37
+ Requires-Dist: requests
38
+ Requires-Dist: pathspec
39
+ Requires-Dist: crontab
40
+ Requires-Dist: setuptools
41
+ Requires-Dist: pytest
42
+ Requires-Dist: pytest-cov
43
+ Requires-Dist: click_completion
44
+
45
+ ```
46
+ .oooooo. oooo .o8 .oooooo..o
47
+ d8P' `Y8b `888 "888 d8P' `Y8
48
+ 888 888 .oooo. oooo oooo .oooo888 .ooooo. Y88bo. oooo ooo ooo. .oo. .ooooo.
49
+ 888 888 `P )88b `888 `888 d88' `888 d88' `88b `"Y8888o. `88. .8' `888P"Y88b d88' `"Y8
50
+ 888 888 .oP"888 888 888 888 888 888ooo888 `"Y88b `88..8' 888 888 888
51
+ `88b ooo 888 d8( 888 888 888 888 888 888 .o oo .d8P `888' 888 888 888 .o8
52
+ `Y8bood8P' o888o `Y888""8o `V88V"V8P' `Y8bod88P" `Y8bod8P' 8""88888P' .8' o888o o888o `Y8bod8P'
53
+ .o..P'
54
+ `Y8P'
55
+ ```
56
+ ![License](https://img.shields.io/badge/License-MIT-blue.svg)
57
+ [![PyPI version](https://badge.fury.io/py/claudesync.svg)](https://badge.fury.io/py/claudesync)
58
+
59
+ ClaudeSync is a powerful tool designed to seamlessly synchronize your local files with [Claude.ai](https://www.anthropic.com/claude) projects.
60
+
61
+ ## Overview and Scope
62
+
63
+ ClaudeSync bridges the gap between your local development environment and Claude.ai's knowledge base. At a high level, the scope of ClaudeSync includes:
64
+
65
+ - Real-time synchronization with Claude.ai projects
66
+ - Command-line interface (CLI) for easy management
67
+ - Multiple organization and project support
68
+ - Automatic handling of file creation, modification, and deletion
69
+ - Intelligent file filtering based on .gitignore rules
70
+ - Configurable sync interval with cron job support
71
+ - Seamless integration with your existing workflow
72
+
73
+ ## Roadmap
74
+
75
+ 1. Enhanced support for large file synchronization
76
+ 2. Improved conflict resolution mechanisms
77
+ 3. GUI client for easier management
78
+ 4. Integration with popular IDEs and text editors
79
+ 5. Support for additional AI platforms beyond Claude.ai
80
+
81
+ ## Quick Start
82
+
83
+ 1. **Install ClaudeSync:**
84
+ ```bash
85
+ pip install claudesync
86
+ ```
87
+
88
+ 2. **Login to Claude.ai:**
89
+ ```bash
90
+ claudesync login claude.ai
91
+ ```
92
+
93
+ 3. **Select an organization:**
94
+ ```bash
95
+ claudesync organization select
96
+ ```
97
+
98
+ 4. **Select or create a project:**
99
+ ```bash
100
+ claudesync project select
101
+ # or
102
+ claudesync project create
103
+ ```
104
+
105
+ 5. **Start syncing:**
106
+ ```bash
107
+ claudesync sync
108
+ ```
109
+
110
+ ## Advanced Usage
111
+
112
+ ### Organization Management
113
+ - List organizations: `claudesync organization ls`
114
+ - Select active organization: `claudesync organization select`
115
+
116
+ ### Project Management
117
+ - List projects: `claudesync project ls`
118
+ - Create a new project: `claudesync project create`
119
+ - Archive a project: `claudesync project archive`
120
+ - Select active project: `claudesync project select`
121
+
122
+ ### File Management
123
+ - List remote files: `claudesync ls`
124
+ - Sync files: `claudesync sync`
125
+
126
+ ### Configuration
127
+ - View current status: `claudesync status`
128
+
129
+ ### Scheduled Sync
130
+ Set up automatic syncing at regular intervals:
131
+ ```bash
132
+ claudesync schedule
133
+ ```
134
+
135
+ ## Contributing
136
+
137
+ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for more information.
138
+
139
+ ## Communication Channels
140
+
141
+ - **Issues**: For bug reports and feature requests, please use our [GitHub Issues](https://github.com/jahwag/claudesync/issues).
142
+
143
+ ## License
144
+
145
+ ClaudeSync is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
146
+
147
+ ## Related Projects
148
+
149
+ - [Claude.ai](https://www.anthropic.com/claude): The AI assistant that ClaudeSync integrates with.
150
+
151
+ ---
152
+
153
+ Made with ❤️ by the ClaudeSync team
@@ -0,0 +1,109 @@
1
+ ```
2
+ .oooooo. oooo .o8 .oooooo..o
3
+ d8P' `Y8b `888 "888 d8P' `Y8
4
+ 888 888 .oooo. oooo oooo .oooo888 .ooooo. Y88bo. oooo ooo ooo. .oo. .ooooo.
5
+ 888 888 `P )88b `888 `888 d88' `888 d88' `88b `"Y8888o. `88. .8' `888P"Y88b d88' `"Y8
6
+ 888 888 .oP"888 888 888 888 888 888ooo888 `"Y88b `88..8' 888 888 888
7
+ `88b ooo 888 d8( 888 888 888 888 888 888 .o oo .d8P `888' 888 888 888 .o8
8
+ `Y8bood8P' o888o `Y888""8o `V88V"V8P' `Y8bod88P" `Y8bod8P' 8""88888P' .8' o888o o888o `Y8bod8P'
9
+ .o..P'
10
+ `Y8P'
11
+ ```
12
+ ![License](https://img.shields.io/badge/License-MIT-blue.svg)
13
+ [![PyPI version](https://badge.fury.io/py/claudesync.svg)](https://badge.fury.io/py/claudesync)
14
+
15
+ ClaudeSync is a powerful tool designed to seamlessly synchronize your local files with [Claude.ai](https://www.anthropic.com/claude) projects.
16
+
17
+ ## Overview and Scope
18
+
19
+ ClaudeSync bridges the gap between your local development environment and Claude.ai's knowledge base. At a high level, the scope of ClaudeSync includes:
20
+
21
+ - Real-time synchronization with Claude.ai projects
22
+ - Command-line interface (CLI) for easy management
23
+ - Multiple organization and project support
24
+ - Automatic handling of file creation, modification, and deletion
25
+ - Intelligent file filtering based on .gitignore rules
26
+ - Configurable sync interval with cron job support
27
+ - Seamless integration with your existing workflow
28
+
29
+ ## Roadmap
30
+
31
+ 1. Enhanced support for large file synchronization
32
+ 2. Improved conflict resolution mechanisms
33
+ 3. GUI client for easier management
34
+ 4. Integration with popular IDEs and text editors
35
+ 5. Support for additional AI platforms beyond Claude.ai
36
+
37
+ ## Quick Start
38
+
39
+ 1. **Install ClaudeSync:**
40
+ ```bash
41
+ pip install claudesync
42
+ ```
43
+
44
+ 2. **Login to Claude.ai:**
45
+ ```bash
46
+ claudesync login claude.ai
47
+ ```
48
+
49
+ 3. **Select an organization:**
50
+ ```bash
51
+ claudesync organization select
52
+ ```
53
+
54
+ 4. **Select or create a project:**
55
+ ```bash
56
+ claudesync project select
57
+ # or
58
+ claudesync project create
59
+ ```
60
+
61
+ 5. **Start syncing:**
62
+ ```bash
63
+ claudesync sync
64
+ ```
65
+
66
+ ## Advanced Usage
67
+
68
+ ### Organization Management
69
+ - List organizations: `claudesync organization ls`
70
+ - Select active organization: `claudesync organization select`
71
+
72
+ ### Project Management
73
+ - List projects: `claudesync project ls`
74
+ - Create a new project: `claudesync project create`
75
+ - Archive a project: `claudesync project archive`
76
+ - Select active project: `claudesync project select`
77
+
78
+ ### File Management
79
+ - List remote files: `claudesync ls`
80
+ - Sync files: `claudesync sync`
81
+
82
+ ### Configuration
83
+ - View current status: `claudesync status`
84
+
85
+ ### Scheduled Sync
86
+ Set up automatic syncing at regular intervals:
87
+ ```bash
88
+ claudesync schedule
89
+ ```
90
+
91
+ ## Contributing
92
+
93
+ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for more information.
94
+
95
+ ## Communication Channels
96
+
97
+ - **Issues**: For bug reports and feature requests, please use our [GitHub Issues](https://github.com/jahwag/claudesync/issues).
98
+
99
+ ## License
100
+
101
+ ClaudeSync is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
102
+
103
+ ## Related Projects
104
+
105
+ - [Claude.ai](https://www.anthropic.com/claude): The AI assistant that ClaudeSync integrates with.
106
+
107
+ ---
108
+
109
+ Made with ❤️ by the ClaudeSync team
@@ -4,22 +4,28 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "claudesync"
7
- version = "0.2.7"
7
+ version = "0.2.9"
8
8
  authors = [
9
9
  {name = "Jahziah Wagner", email = "jahziah.wagner+pypi@gmail.com"},
10
10
  ]
11
11
  description = "A tool to synchronize local files with Claude.ai projects"
12
+ license = {file = "LICENSE"}
12
13
  readme = "README.md"
13
- requires-python = ">=3.6"
14
+ requires-python = ">=3.7"
14
15
  classifiers = [
15
16
  "Programming Language :: Python :: 3",
16
17
  "License :: OSI Approved :: MIT License",
17
18
  "Operating System :: OS Independent",
18
19
  ]
19
20
  dependencies = [
20
- "watchdog",
21
+ "Click",
21
22
  "requests",
22
23
  "pathspec",
24
+ "crontab",
25
+ "setuptools",
26
+ "pytest",
27
+ "pytest-cov",
28
+ "click_completion",
23
29
  ]
24
30
 
25
31
  [project.urls]
@@ -27,7 +33,14 @@ dependencies = [
27
33
  "Bug Tracker" = "https://github.com/jahwag/claudesync/issues"
28
34
 
29
35
  [project.scripts]
30
- claudesync = "claudesync.main:main"
36
+ claudesync = "claudesync.cli.main:cli"
31
37
 
32
38
  [tool.setuptools.packages.find]
33
39
  where = ["src"]
40
+ include = ["claudesync*"]
41
+
42
+
43
+ [tool.pytest.ini_options]
44
+ testpaths = ["tests"]
45
+ python_files = "test_*.py"
46
+ addopts = "-v --cov=claudesync --cov-report=term-missing"
@@ -3,4 +3,4 @@ from setuptools import setup, find_packages
3
3
  setup(
4
4
  packages=find_packages(where="src"),
5
5
  package_dir={"": "src"},
6
- )
6
+ )
File without changes
@@ -0,0 +1,3 @@
1
+ from .main import cli
2
+
3
+ __all__ = ["cli"]
@@ -0,0 +1,34 @@
1
+ import click
2
+ from claudesync.provider_factory import get_provider
3
+ from ..utils import handle_errors
4
+
5
+
6
+ @click.command()
7
+ @click.argument("provider", required=False)
8
+ @click.pass_obj
9
+ @handle_errors
10
+ def login(config, provider):
11
+ """Authenticate with an AI provider."""
12
+ providers = get_provider()
13
+ if not provider:
14
+ click.echo("Available providers:\n" + "\n".join(f" - {p}" for p in providers))
15
+ return
16
+ if provider not in providers:
17
+ click.echo(
18
+ f"Error: Unknown provider '{provider}'. Available: {', '.join(providers)}"
19
+ )
20
+ return
21
+ provider_instance = get_provider(provider)
22
+ session_key = provider_instance.login()
23
+ config.set("session_key", session_key)
24
+ config.set("active_provider", provider)
25
+ click.echo("Logged in successfully.")
26
+
27
+
28
+ @click.command()
29
+ @click.pass_obj
30
+ def logout(config):
31
+ """Log out from the current AI provider."""
32
+ for key in ["session_key", "active_provider", "active_organization_id"]:
33
+ config.set(key, None)
34
+ click.echo("Logged out successfully.")
@@ -0,0 +1,60 @@
1
+ import click
2
+ from claudesync.config_manager import ConfigManager
3
+ import click_completion
4
+ import click_completion.core
5
+
6
+ # Import commands from other CLI files
7
+ from .auth import login, logout
8
+ from .organization import organization
9
+ from .project import project
10
+ from .sync import ls, sync, schedule
11
+
12
+ click_completion.init()
13
+
14
+
15
+ @click.group()
16
+ @click.pass_context
17
+ def cli(ctx):
18
+ """ClaudeSync: Synchronize local files with ai projects."""
19
+ ctx.obj = ConfigManager()
20
+
21
+
22
+ @cli.command()
23
+ @click.argument(
24
+ "shell", required=False, type=click.Choice(["bash", "zsh", "fish", "powershell"])
25
+ )
26
+ def install_completion(shell):
27
+ """Install completion for the specified shell."""
28
+ if shell is None:
29
+ shell = click_completion.get_auto_shell()
30
+ click.echo("Shell is set to '%s'" % shell)
31
+ click_completion.install(shell=shell)
32
+ click.echo("Completion installed.")
33
+
34
+
35
+ @cli.command()
36
+ @click.pass_obj
37
+ def status(config):
38
+ """Display current configuration status."""
39
+ for key in [
40
+ "active_provider",
41
+ "active_organization_id",
42
+ "active_project_id",
43
+ "active_project_name",
44
+ "local_path",
45
+ "log_level",
46
+ ]:
47
+ value = config.get(key)
48
+ click.echo(f"{key.replace('_', ' ').capitalize()}: {value or 'Not set'}")
49
+
50
+
51
+ cli.add_command(login)
52
+ cli.add_command(logout)
53
+ cli.add_command(organization)
54
+ cli.add_command(project)
55
+ cli.add_command(ls)
56
+ cli.add_command(sync)
57
+ cli.add_command(schedule)
58
+
59
+ if __name__ == "__main__":
60
+ cli()
@@ -0,0 +1,47 @@
1
+ import click
2
+ from ..utils import handle_errors, validate_and_get_provider
3
+
4
+
5
+ @click.group()
6
+ def organization():
7
+ """Manage ai organizations."""
8
+ pass
9
+
10
+
11
+ @organization.command()
12
+ @click.pass_obj
13
+ @handle_errors
14
+ def ls(config):
15
+ """List all available organizations."""
16
+ provider = validate_and_get_provider(config, require_org=False)
17
+ organizations = provider.get_organizations()
18
+ if not organizations:
19
+ click.echo("No organizations found.")
20
+ else:
21
+ click.echo("Available organizations:")
22
+ for idx, org in enumerate(organizations, 1):
23
+ click.echo(f" {idx}. {org['name']} (ID: {org['id']})")
24
+
25
+
26
+ @organization.command()
27
+ @click.pass_obj
28
+ @handle_errors
29
+ def select(config):
30
+ """Set the active organization."""
31
+ provider = validate_and_get_provider(config, require_org=False)
32
+ organizations = provider.get_organizations()
33
+ if not organizations:
34
+ click.echo("No organizations found.")
35
+ return
36
+ click.echo("Available organizations:")
37
+ for idx, org in enumerate(organizations, 1):
38
+ click.echo(f" {idx}. {org['name']} (ID: {org['id']})")
39
+ selection = click.prompt("Enter the number of the organization to select", type=int)
40
+ if 1 <= selection <= len(organizations):
41
+ selected_org = organizations[selection - 1]
42
+ config.set("active_organization_id", selected_org["id"])
43
+ click.echo(
44
+ f"Selected organization: {selected_org['name']} (ID: {selected_org['id']})"
45
+ )
46
+ else:
47
+ click.echo("Invalid selection. Please try again.")
@@ -0,0 +1,122 @@
1
+ import click
2
+ from claudesync.exceptions import ProviderError
3
+ from ..utils import (
4
+ handle_errors,
5
+ validate_and_get_provider,
6
+ validate_and_store_local_path,
7
+ )
8
+
9
+
10
+ @click.group()
11
+ def project():
12
+ """Manage ai projects within the active organization."""
13
+ pass
14
+
15
+
16
+ @project.command()
17
+ @click.pass_obj
18
+ @handle_errors
19
+ def create(config):
20
+ """Create a new project in the active organization."""
21
+ provider = validate_and_get_provider(config)
22
+ active_organization_id = config.get("active_organization_id")
23
+
24
+ title = click.prompt("Enter the project title")
25
+ description = click.prompt("Enter the project description (optional)", default="")
26
+
27
+ try:
28
+ new_project = provider.create_project(
29
+ active_organization_id, title, description
30
+ )
31
+ click.echo(
32
+ f"Project '{new_project['name']}' (uuid: {new_project['uuid']}) has been created successfully."
33
+ )
34
+
35
+ config.set("active_project_id", new_project["uuid"])
36
+ config.set("active_project_name", new_project["name"])
37
+ click.echo(
38
+ f"Active project set to: {new_project['name']} (uuid: {new_project['uuid']})"
39
+ )
40
+
41
+ validate_and_store_local_path(config)
42
+
43
+ except ProviderError as e:
44
+ click.echo(f"Failed to create project: {str(e)}")
45
+
46
+
47
+ @project.command()
48
+ @click.pass_obj
49
+ @handle_errors
50
+ def archive(config):
51
+ """Archive an existing project."""
52
+ provider = validate_and_get_provider(config)
53
+ active_organization_id = config.get("active_organization_id")
54
+ projects = provider.get_projects(active_organization_id, include_archived=False)
55
+ if not projects:
56
+ click.echo("No active projects found.")
57
+ return
58
+ click.echo("Available projects to archive:")
59
+ for idx, project in enumerate(projects, 1):
60
+ click.echo(f" {idx}. {project['name']} (ID: {project['id']})")
61
+ selection = click.prompt("Enter the number of the project to archive", type=int)
62
+ if 1 <= selection <= len(projects):
63
+ selected_project = projects[selection - 1]
64
+ if click.confirm(
65
+ f"Are you sure you want to archive '{selected_project['name']}'?"
66
+ ):
67
+ provider.archive_project(active_organization_id, selected_project["id"])
68
+ click.echo(f"Project '{selected_project['name']}' has been archived.")
69
+ else:
70
+ click.echo("Invalid selection. Please try again.")
71
+
72
+
73
+ @project.command()
74
+ @click.pass_obj
75
+ @handle_errors
76
+ def select(config):
77
+ """Set the active project for syncing."""
78
+ provider = validate_and_get_provider(config)
79
+ active_organization_id = config.get("active_organization_id")
80
+ projects = provider.get_projects(active_organization_id, include_archived=False)
81
+ if not projects:
82
+ click.echo("No active projects found.")
83
+ return
84
+ click.echo("Available projects:")
85
+ for idx, project in enumerate(projects, 1):
86
+ click.echo(f" {idx}. {project['name']} (ID: {project['id']})")
87
+ selection = click.prompt("Enter the number of the project to select", type=int)
88
+ if 1 <= selection <= len(projects):
89
+ selected_project = projects[selection - 1]
90
+ config.set("active_project_id", selected_project["id"])
91
+ config.set("active_project_name", selected_project["name"])
92
+ click.echo(
93
+ f"Selected project: {selected_project['name']} (ID: {selected_project['id']})"
94
+ )
95
+
96
+ validate_and_store_local_path(config)
97
+ else:
98
+ click.echo("Invalid selection. Please try again.")
99
+
100
+
101
+ @project.command()
102
+ @click.option(
103
+ "-a",
104
+ "--all",
105
+ "show_all",
106
+ is_flag=True,
107
+ help="Include archived projects in the list",
108
+ )
109
+ @click.pass_obj
110
+ @handle_errors
111
+ def ls(config, show_all):
112
+ """List all projects in the active organization."""
113
+ provider = validate_and_get_provider(config)
114
+ active_organization_id = config.get("active_organization_id")
115
+ projects = provider.get_projects(active_organization_id, include_archived=show_all)
116
+ if not projects:
117
+ click.echo("No projects found.")
118
+ else:
119
+ click.echo("Remote projects:")
120
+ for project in projects:
121
+ status = " (Archived)" if project.get("archived_at") else ""
122
+ click.echo(f" - {project['name']} (ID: {project['id']}){status}")