claudesync 0.2.6__tar.gz → 0.2.7__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.6/src/claudesync.egg-info → claudesync-0.2.7}/PKG-INFO +1 -1
- {claudesync-0.2.6 → claudesync-0.2.7}/pyproject.toml +1 -1
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/file_handler.py +32 -12
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/main.py +11 -4
- {claudesync-0.2.6 → claudesync-0.2.7/src/claudesync.egg-info}/PKG-INFO +1 -1
- {claudesync-0.2.6 → claudesync-0.2.7}/LICENSE +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/README.md +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/setup.cfg +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/setup.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/__init__.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/api_utils.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/debounce.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/gitignore_utils.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync/manual_auth.py +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync.egg-info/SOURCES.txt +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync.egg-info/dependency_links.txt +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync.egg-info/entry_points.txt +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync.egg-info/requires.txt +0 -0
- {claudesync-0.2.6 → claudesync-0.2.7}/src/claudesync.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: claudesync
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: A tool to synchronize local files with Claude.ai projects
|
|
5
5
|
Author-email: Jahziah Wagner <jahziah.wagner+pypi@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/jahwag/claudesync
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import mimetypes
|
|
3
|
+
import time
|
|
3
4
|
from watchdog.events import FileSystemEventHandler
|
|
4
5
|
from .debounce import DebounceHandler
|
|
5
6
|
from .gitignore_utils import load_gitignore, should_ignore
|
|
@@ -21,6 +22,10 @@ class FileUploadHandler(FileSystemEventHandler):
|
|
|
21
22
|
self.gitignore = load_gitignore(self.base_path)
|
|
22
23
|
self.log_callback = None
|
|
23
24
|
self.max_file_size = max_file_size
|
|
25
|
+
self.backoff_time = 1
|
|
26
|
+
self.max_backoff_time = 60
|
|
27
|
+
self.session_expiration_time = 180 # 3 minutes
|
|
28
|
+
self.session_expiration_start = None
|
|
24
29
|
|
|
25
30
|
def log(self, message):
|
|
26
31
|
if self.log_callback:
|
|
@@ -57,37 +62,52 @@ class FileUploadHandler(FileSystemEventHandler):
|
|
|
57
62
|
return should_ignore(self.gitignore, file_path, self.base_path)
|
|
58
63
|
|
|
59
64
|
def api_request(self, method, url, **kwargs):
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
while True:
|
|
66
|
+
try:
|
|
67
|
+
response = requests.request(method, url, headers=self.headers, cookies=self.cookies, **kwargs)
|
|
68
|
+
if response.status_code == 403:
|
|
69
|
+
if self.session_expiration_start is None:
|
|
70
|
+
self.session_expiration_start = time.time()
|
|
71
|
+
elif time.time() - self.session_expiration_start > self.session_expiration_time:
|
|
72
|
+
self.log("Session key has likely expired. Please restart ClaudeSync with a new session key.")
|
|
73
|
+
raise SystemExit(1)
|
|
74
|
+
|
|
75
|
+
self.log(f"Received 403 error. Backing off for {self.backoff_time} seconds.")
|
|
76
|
+
time.sleep(self.backoff_time)
|
|
77
|
+
self.backoff_time = min(self.backoff_time * 2, self.max_backoff_time)
|
|
78
|
+
else:
|
|
79
|
+
self.session_expiration_start = None
|
|
80
|
+
self.backoff_time = 1
|
|
81
|
+
response.raise_for_status()
|
|
82
|
+
return response.json() if response.text else None
|
|
83
|
+
except requests.RequestException as e:
|
|
84
|
+
if response.status_code != 403:
|
|
85
|
+
self.log(f"API request error: {str(e)}")
|
|
86
|
+
return None
|
|
67
87
|
|
|
68
88
|
def get_documents(self):
|
|
69
89
|
return self.api_request('GET', self.api_endpoint) or []
|
|
70
90
|
|
|
71
91
|
def delete_document(self, uuid):
|
|
72
92
|
if self.api_request('DELETE', f"{self.api_endpoint}/{uuid}"):
|
|
73
|
-
|
|
93
|
+
self.log(f"Deleted document: {uuid}")
|
|
74
94
|
|
|
75
95
|
def delete_all_documents(self):
|
|
76
96
|
for doc in self.get_documents():
|
|
77
97
|
self.delete_document(doc['uuid'])
|
|
78
|
-
|
|
98
|
+
self.log("All documents deleted.")
|
|
79
99
|
|
|
80
100
|
def upload_file(self, file_path):
|
|
81
101
|
if not os.path.isfile(file_path) or self.should_ignore_file(file_path):
|
|
82
102
|
return
|
|
83
103
|
if os.path.getsize(file_path) == 0:
|
|
84
|
-
|
|
104
|
+
self.log(f"Skipping empty file: {file_path}")
|
|
85
105
|
return
|
|
86
106
|
try:
|
|
87
107
|
with open(file_path, 'r', encoding='utf-8') as file:
|
|
88
108
|
content = file.read()
|
|
89
109
|
if not content.strip():
|
|
90
|
-
|
|
110
|
+
self.log(f"Skipping file with only whitespace: {file_path}")
|
|
91
111
|
return
|
|
92
112
|
|
|
93
113
|
rel_path = os.path.relpath(file_path, self.base_path)
|
|
@@ -100,4 +120,4 @@ class FileUploadHandler(FileSystemEventHandler):
|
|
|
100
120
|
if self.api_request('POST', self.api_endpoint, json=payload):
|
|
101
121
|
self.log(f"Uploaded: {file_name}")
|
|
102
122
|
except Exception as e:
|
|
103
|
-
|
|
123
|
+
self.log(f"Error processing file {file_path}: {str(e)}")
|
|
@@ -21,8 +21,9 @@ class ClaudeSyncTUI:
|
|
|
21
21
|
self.observer = None
|
|
22
22
|
self.handler = None
|
|
23
23
|
self.scroll_position = 0
|
|
24
|
-
self.max_log_lines = 1000
|
|
25
|
-
self.auto_scroll = True
|
|
24
|
+
self.max_log_lines = 1000
|
|
25
|
+
self.auto_scroll = True
|
|
26
|
+
self.is_syncing = False
|
|
26
27
|
|
|
27
28
|
def setup(self):
|
|
28
29
|
if not self.user_id:
|
|
@@ -39,14 +40,16 @@ class ClaudeSyncTUI:
|
|
|
39
40
|
self.observer.schedule(self.handler, self.watch_dir, recursive=True)
|
|
40
41
|
|
|
41
42
|
def initial_sync(self):
|
|
42
|
-
|
|
43
|
-
self.add_log_message("
|
|
43
|
+
self.is_syncing = True
|
|
44
|
+
self.add_log_message("Starting initial synchronization...")
|
|
44
45
|
for root, dirs, files in os.walk(self.watch_dir):
|
|
45
46
|
for file in files:
|
|
46
47
|
file_path = os.path.join(root, file)
|
|
47
48
|
if not self.handler.should_ignore_file(file_path):
|
|
48
49
|
self.handler.upload_file(file_path)
|
|
50
|
+
self.draw() # Redraw the TUI after each file upload
|
|
49
51
|
self.add_log_message("Initial synchronization completed.")
|
|
52
|
+
self.is_syncing = False
|
|
50
53
|
|
|
51
54
|
def add_log_message(self, message):
|
|
52
55
|
self.log_messages.append(message)
|
|
@@ -68,6 +71,9 @@ class ClaudeSyncTUI:
|
|
|
68
71
|
print(f"Project ID: {self.project_id}")
|
|
69
72
|
print(f"Auto-scroll: {'ON' if self.auto_scroll else 'OFF'}")
|
|
70
73
|
|
|
74
|
+
if self.is_syncing:
|
|
75
|
+
print(self.term.move_y(7) + self.term.red("Initial sync in progress..."))
|
|
76
|
+
|
|
71
77
|
print(self.term.move_y(8) + self.term.black_on_skyblue(self.term.center('Recent Activity')))
|
|
72
78
|
|
|
73
79
|
log_height = self.term.height - 12
|
|
@@ -79,6 +85,7 @@ class ClaudeSyncTUI:
|
|
|
79
85
|
|
|
80
86
|
def run(self):
|
|
81
87
|
with self.term.cbreak(), self.term.hidden_cursor():
|
|
88
|
+
self.draw() # Initial draw before starting sync
|
|
82
89
|
self.initial_sync()
|
|
83
90
|
self.observer.start()
|
|
84
91
|
while True:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: claudesync
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: A tool to synchronize local files with Claude.ai projects
|
|
5
5
|
Author-email: Jahziah Wagner <jahziah.wagner+pypi@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/jahwag/claudesync
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|