codedthemes-cli 0.1.14__tar.gz → 0.1.16__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.
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/PKG-INFO +1 -1
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/cli.py +71 -33
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/PKG-INFO +1 -1
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/pyproject.toml +1 -1
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/README.md +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/__init__.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/config.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/mcp_client.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/patch_utils.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/repo_utils.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes/sync_manager.py +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/SOURCES.txt +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/dependency_links.txt +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/entry_points.txt +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/requires.txt +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/top_level.txt +0 -0
- {codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/setup.cfg +0 -0
|
@@ -151,6 +151,14 @@ def handle_init():
|
|
|
151
151
|
|
|
152
152
|
repo_abs_path = os.path.abspath(repo_root)
|
|
153
153
|
repo_key = repo_abs_path.lower().replace(os.sep, "/")
|
|
154
|
+
|
|
155
|
+
# Check if already initialized to avoid redundant uploads
|
|
156
|
+
config = load_config()
|
|
157
|
+
existing_ws_id = config.get("workspaces", {}).get(repo_key)
|
|
158
|
+
if existing_ws_id:
|
|
159
|
+
# Fast check: exists?
|
|
160
|
+
pass # We could call a /verify endpoint here, but for now let's just proceed with upload as "sync"
|
|
161
|
+
|
|
154
162
|
print("📦 Zipping and uploading repository (this may take a moment)...")
|
|
155
163
|
upload_result = client.upload_workspace(repo_abs_path, user_email)
|
|
156
164
|
workspace_id = upload_result.get("workspace_id")
|
|
@@ -232,10 +240,29 @@ def handle_init():
|
|
|
232
240
|
sys.exit(1)
|
|
233
241
|
|
|
234
242
|
|
|
243
|
+
def clean_remote_path(p: str) -> str:
|
|
244
|
+
"""
|
|
245
|
+
Strips the deeply nested remote container path if present.
|
|
246
|
+
e.g., 'home/runner/work/<owner>/<repo>/src/...' -> 'src/...'
|
|
247
|
+
"""
|
|
248
|
+
if not p: return p
|
|
249
|
+
p = p.replace('\\', '/')
|
|
250
|
+
if p.startswith('/'): p = p[1:]
|
|
251
|
+
if p.startswith('home/runner/work/'):
|
|
252
|
+
parts = p.split('/')
|
|
253
|
+
if len(parts) > 4: # e.g. ['home', 'runner', 'work', 'owner', 'repo', 'src', ...]
|
|
254
|
+
return '/'.join(parts[5:])
|
|
255
|
+
return p
|
|
256
|
+
|
|
235
257
|
def handle_apply(query: str):
|
|
236
258
|
"""
|
|
237
259
|
Plans and executes changes based on a natural language query.
|
|
238
260
|
"""
|
|
261
|
+
if not query or not query.strip():
|
|
262
|
+
print("✖ Error: Query cannot be empty.")
|
|
263
|
+
print("💡 Example: codedthemes apply \"Update the primary color to deep purple\"")
|
|
264
|
+
return
|
|
265
|
+
|
|
239
266
|
try:
|
|
240
267
|
repo_root = detect_repo_root()
|
|
241
268
|
repo_abs_path = os.path.abspath(repo_root)
|
|
@@ -327,10 +354,10 @@ def handle_apply(query: str):
|
|
|
327
354
|
print(f"✖ Planning failed: {plan.get('message', 'Unknown error')}")
|
|
328
355
|
return
|
|
329
356
|
|
|
330
|
-
target_files = plan.get("files_to_modify", [])
|
|
357
|
+
target_files = [clean_remote_path(f) for f in plan.get("files_to_modify", [])]
|
|
331
358
|
instructions = plan.get("plan_instructions", [])
|
|
332
|
-
files_to_create = plan.get("files_to_create", [])
|
|
333
|
-
files_to_delete = plan.get("files_to_delete", [])
|
|
359
|
+
files_to_create = [clean_remote_path(f) for f in plan.get("files_to_create", [])]
|
|
360
|
+
files_to_delete = [clean_remote_path(f) for f in plan.get("files_to_delete", [])]
|
|
334
361
|
|
|
335
362
|
if not any([target_files, files_to_create, files_to_delete, instructions]):
|
|
336
363
|
print("Information: No changes planned.")
|
|
@@ -388,41 +415,52 @@ def handle_apply(query: str):
|
|
|
388
415
|
updates = res_data.get("updates_for_local", [])
|
|
389
416
|
deletes = res_data.get("deleted_files", [])
|
|
390
417
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
418
|
+
# 1. Apply local updates
|
|
419
|
+
for item in updates:
|
|
420
|
+
rel_path = clean_remote_path(item.get("path"))
|
|
421
|
+
code = item.get("code")
|
|
422
|
+
if not rel_path or code is None: continue
|
|
423
|
+
abs_path = os.path.abspath(os.path.join(repo_abs_path, rel_path.replace('/', os.sep)))
|
|
424
|
+
|
|
425
|
+
try:
|
|
426
|
+
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
|
|
427
|
+
with open(abs_path, 'w', encoding='utf-8') as f:
|
|
428
|
+
f.write(code)
|
|
429
|
+
print(f"✔ Updated: {rel_path}")
|
|
430
|
+
except Exception as e:
|
|
431
|
+
print(f"✖ Error writing {rel_path}: {e}")
|
|
396
432
|
|
|
433
|
+
# 2. Apply local deletions
|
|
434
|
+
for rel_path_raw in (deletes or []):
|
|
435
|
+
rel_path = clean_remote_path(rel_path_raw)
|
|
436
|
+
abs_path = os.path.normpath(os.path.join(repo_abs_path, rel_path.replace('/', os.sep)))
|
|
437
|
+
if os.path.exists(abs_path) and abs_path.startswith(os.path.abspath(repo_abs_path)):
|
|
397
438
|
try:
|
|
398
|
-
os.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
for rel_path in (deletes or []):
|
|
406
|
-
abs_path = os.path.normpath(os.path.join(repo_abs_path, rel_path.replace('/', os.sep)))
|
|
407
|
-
if os.path.exists(abs_path) and abs_path.startswith(os.path.abspath(repo_abs_path)):
|
|
408
|
-
try:
|
|
409
|
-
if os.path.isfile(abs_path): os.remove(abs_path)
|
|
410
|
-
elif os.path.isdir(abs_path): shutil.rmtree(abs_path)
|
|
411
|
-
print(f"✔ Deleted: {rel_path}")
|
|
412
|
-
except: pass
|
|
413
|
-
|
|
439
|
+
if os.path.isfile(abs_path): os.remove(abs_path)
|
|
440
|
+
elif os.path.isdir(abs_path): shutil.rmtree(abs_path)
|
|
441
|
+
print(f"✔ Deleted: {rel_path}")
|
|
442
|
+
except: pass
|
|
443
|
+
|
|
444
|
+
# 3. Synchronize state
|
|
445
|
+
if updates or deletes:
|
|
414
446
|
sync_manager.update_sync_state(repo_abs_path, workspace_id, user_email)
|
|
415
447
|
print("✔ Local sync state updated.")
|
|
416
448
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
449
|
+
# 4. Show Integration Report (Always show errors or details)
|
|
450
|
+
_details_raw = res_data.get("details", [])
|
|
451
|
+
details_list = _details_raw.get("report", []) if isinstance(_details_raw, dict) else (_details_raw if isinstance(_details_raw, list) else [])
|
|
452
|
+
if details_list:
|
|
453
|
+
print("\n📊 Integration Report:")
|
|
454
|
+
for item in details_list:
|
|
455
|
+
status_icon = "✔" if item.get("success") else "✖"
|
|
456
|
+
print(f" [{status_icon}] {item.get('file_path')}: {item.get('message', '')}")
|
|
457
|
+
|
|
458
|
+
# 5. Output Final Message if no updates were applied
|
|
459
|
+
if not updates and not deletes:
|
|
460
|
+
msg = res_data.get('message', 'Changes applied successfully.')
|
|
461
|
+
if isinstance(msg, str) and "AI MUST now sync" in msg:
|
|
462
|
+
msg = msg.split("AI MUST now sync")[0].strip()
|
|
463
|
+
print(f"✔ {msg}")
|
|
426
464
|
|
|
427
465
|
except Exception as e:
|
|
428
466
|
print(f"✖ Error: {e}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codedthemes_cli-0.1.14 → codedthemes_cli-0.1.16}/codedthemes_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|