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.
- {claudesync-0.2.7 → claudesync-0.2.9}/LICENSE +1 -1
- claudesync-0.2.9/PKG-INFO +153 -0
- claudesync-0.2.9/README.md +109 -0
- {claudesync-0.2.7 → claudesync-0.2.9}/pyproject.toml +17 -4
- {claudesync-0.2.7 → claudesync-0.2.9}/setup.py +1 -1
- claudesync-0.2.9/src/claudesync/__init__.py +0 -0
- claudesync-0.2.9/src/claudesync/cli/__init__.py +3 -0
- claudesync-0.2.9/src/claudesync/cli/auth.py +34 -0
- claudesync-0.2.9/src/claudesync/cli/main.py +60 -0
- claudesync-0.2.9/src/claudesync/cli/organization.py +47 -0
- claudesync-0.2.9/src/claudesync/cli/project.py +122 -0
- claudesync-0.2.9/src/claudesync/cli/sync.py +120 -0
- claudesync-0.2.9/src/claudesync/config_manager.py +30 -0
- claudesync-0.2.9/src/claudesync/exceptions.py +10 -0
- claudesync-0.2.9/src/claudesync/provider_factory.py +19 -0
- claudesync-0.2.9/src/claudesync/providers/__init__.py +0 -0
- claudesync-0.2.9/src/claudesync/providers/claude_ai.py +166 -0
- claudesync-0.2.9/src/claudesync/utils.py +122 -0
- claudesync-0.2.9/src/claudesync.egg-info/PKG-INFO +153 -0
- claudesync-0.2.9/src/claudesync.egg-info/SOURCES.txt +29 -0
- claudesync-0.2.9/src/claudesync.egg-info/entry_points.txt +2 -0
- claudesync-0.2.9/src/claudesync.egg-info/requires.txt +8 -0
- claudesync-0.2.9/tests/test_auth.py +29 -0
- claudesync-0.2.9/tests/test_main.py +29 -0
- claudesync-0.2.9/tests/test_organization.py +81 -0
- claudesync-0.2.9/tests/test_project.py +128 -0
- claudesync-0.2.9/tests/test_sync.py +147 -0
- claudesync-0.2.9/tests/test_utils.py +59 -0
- claudesync-0.2.7/PKG-INFO +0 -85
- claudesync-0.2.7/README.md +0 -68
- claudesync-0.2.7/src/claudesync/__init__.py +0 -7
- claudesync-0.2.7/src/claudesync/api_utils.py +0 -94
- claudesync-0.2.7/src/claudesync/debounce.py +0 -21
- claudesync-0.2.7/src/claudesync/file_handler.py +0 -123
- claudesync-0.2.7/src/claudesync/gitignore_utils.py +0 -31
- claudesync-0.2.7/src/claudesync/main.py +0 -163
- claudesync-0.2.7/src/claudesync/manual_auth.py +0 -77
- claudesync-0.2.7/src/claudesync.egg-info/PKG-INFO +0 -85
- claudesync-0.2.7/src/claudesync.egg-info/SOURCES.txt +0 -17
- claudesync-0.2.7/src/claudesync.egg-info/entry_points.txt +0 -2
- claudesync-0.2.7/src/claudesync.egg-info/requires.txt +0 -3
- {claudesync-0.2.7 → claudesync-0.2.9}/setup.cfg +0 -0
- {claudesync-0.2.7 → claudesync-0.2.9}/src/claudesync.egg-info/dependency_links.txt +0 -0
- {claudesync-0.2.7 → claudesync-0.2.9}/src/claudesync.egg-info/top_level.txt +0 -0
|
@@ -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
|
+

|
|
57
|
+
[](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
|
+

|
|
13
|
+
[](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
|
+
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.
|
|
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
|
-
"
|
|
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:
|
|
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"
|
|
File without changes
|
|
@@ -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}")
|