|
14 | 14 | from urllib.request import urlopen |
15 | 15 |
|
16 | 16 | from rich.console import Console |
17 | | -from rich.prompt import Confirm, Prompt |
| 17 | +from rich.prompt import Prompt |
18 | 18 |
|
19 | 19 | from .events import ( |
20 | 20 | send_event, |
|
23 | 23 | SkillInstallCompletedEvent, |
24 | 24 | SkillInstallFailedEvent, |
25 | 25 | ) |
26 | | -from .utils import copy_directory, copy_file, read_from_path, write_to_path |
| 26 | +from .utils import copy_directory, copy_file |
27 | 27 |
|
28 | 28 |
|
29 | 29 | # ============================================================================= |
@@ -69,20 +69,10 @@ class SafetyError(SetupError): |
69 | 69 | WECO_SKILL_DIR = CLAUDE_SKILLS_DIR / "weco" |
70 | 70 | WECO_CLAUDE_SNIPPET_PATH = WECO_SKILL_DIR / "snippets" / "claude.md" |
71 | 71 | WECO_CLAUDE_MD_PATH = WECO_SKILL_DIR / "CLAUDE.md" |
72 | | -CLAUDE_MD_PATH = CLAUDE_DIR / "CLAUDE.md" |
73 | | -WECO_CLAUDE_GLOBAL_SNIPPET_PATH = WECO_SKILL_DIR / "snippets" / "claude-global.md" |
74 | | - |
75 | | -# Section markers for the global ~/.claude/CLAUDE.md |
76 | | -WECO_SECTION_START = "<!-- WECO_START -->" |
77 | | -WECO_SECTION_END = "<!-- WECO_END -->" |
78 | | - |
79 | 72 | # Cursor paths |
80 | 73 | CURSOR_DIR = pathlib.Path.home() / ".cursor" |
81 | | -CURSOR_RULES_DIR = CURSOR_DIR / "rules" |
82 | | -CURSOR_WECO_RULES_PATH = CURSOR_RULES_DIR / "weco.mdc" |
83 | 74 | CURSOR_SKILLS_DIR = CURSOR_DIR / "skills" |
84 | 75 | CURSOR_WECO_SKILL_DIR = CURSOR_SKILLS_DIR / "weco" |
85 | | -CURSOR_RULES_SNIPPET_PATH = CURSOR_WECO_SKILL_DIR / "snippets" / "cursor.md" |
86 | 76 |
|
87 | 77 | # Files/directories to skip when copying local repos |
88 | 78 | _COPY_IGNORE_PATTERNS = {".git", "__pycache__", ".DS_Store"} |
@@ -175,53 +165,6 @@ def safe_remove_directory(path: pathlib.Path, allowed_parents: set[pathlib.Path] |
175 | 165 | # ============================================================================= |
176 | 166 |
|
177 | 167 |
|
178 | | -def generate_cursor_mdc_content(snippet_content: str) -> str: |
179 | | - """Generate Cursor MDC file content with YAML frontmatter.""" |
180 | | - return f"""--- |
181 | | -description: Weco code optimization skill. Weco automates optimization by iteratively refining code against any metric you define — invoke for speed, accuracy, latency, cost, or anything else you can measure. |
182 | | -alwaysApply: true |
183 | | ---- |
184 | | -{snippet_content} |
185 | | -""" |
186 | | - |
187 | | - |
188 | | -def generate_weco_claude_section(snippet_content: str) -> str: |
189 | | - """Generate the Weco section for the global ~/.claude/CLAUDE.md with marker tags.""" |
190 | | - return f"""{WECO_SECTION_START} |
191 | | -{snippet_content} |
192 | | -{WECO_SECTION_END}""" |
193 | | - |
194 | | - |
195 | | -def extract_weco_section(content: str) -> str | None: |
196 | | - """Extract the Weco section from file content, or None if not present.""" |
197 | | - if WECO_SECTION_START not in content or WECO_SECTION_END not in content: |
198 | | - return None |
199 | | - start = content.index(WECO_SECTION_START) |
200 | | - end = content.index(WECO_SECTION_END) + len(WECO_SECTION_END) |
201 | | - return content[start:end] |
202 | | - |
203 | | - |
204 | | -def upsert_weco_section(file_path: pathlib.Path, section: str) -> None: |
205 | | - """ |
206 | | - Insert or replace the Weco section in a file. |
207 | | -
|
208 | | - - If the file has existing WECO_START/WECO_END markers, replace that region. |
209 | | - - If the file exists but has no markers, append the section. |
210 | | - - If the file doesn't exist, create it with the section. |
211 | | - """ |
212 | | - if file_path.exists(): |
213 | | - content = read_from_path(file_path) |
214 | | - existing = extract_weco_section(content) |
215 | | - if existing is not None: |
216 | | - content = content.replace(existing, section) |
217 | | - else: |
218 | | - content = content.rstrip() + "\n\n" + section + "\n" |
219 | | - else: |
220 | | - content = section + "\n" |
221 | | - |
222 | | - write_to_path(file_path, content, mkdir=True) |
223 | | - |
224 | | - |
225 | 168 | def validate_local_skill_repo(local_path: pathlib.Path) -> None: |
226 | 169 | """ |
227 | 170 | Validate that a local path is a valid weco-skill repository. |
@@ -413,96 +356,22 @@ def setup_claude_code(console: Console, local_path: pathlib.Path | None = None) |
413 | 356 | copy_file(WECO_CLAUDE_SNIPPET_PATH, WECO_CLAUDE_MD_PATH) |
414 | 357 | console.print("[green]CLAUDE.md installed to skill directory.[/]") |
415 | 358 |
|
416 | | - # Update global ~/.claude/CLAUDE.md with a Weco section. |
417 | | - # The global file is user-managed and may contain other content, so we use |
418 | | - # section markers (WECO_START/WECO_END) to insert or replace only our section. |
419 | | - snippet_content = read_from_path(WECO_CLAUDE_GLOBAL_SNIPPET_PATH) |
420 | | - section = generate_weco_claude_section(snippet_content.strip()) |
421 | | - |
422 | | - existing_content = None |
423 | | - if CLAUDE_MD_PATH.exists(): |
424 | | - try: |
425 | | - existing_content = read_from_path(CLAUDE_MD_PATH) |
426 | | - except Exception: |
427 | | - pass |
428 | | - |
429 | | - existing_section = extract_weco_section(existing_content) if existing_content else None |
430 | | - |
431 | | - if existing_section is not None and existing_section.strip() == section.strip(): |
432 | | - console.print("[dim]~/.claude/CLAUDE.md already contains the latest Weco section.[/]") |
433 | | - else: |
434 | | - action = "updated" if existing_section is not None else "added" |
435 | | - console.print("\n[bold yellow]~/.claude/CLAUDE.md Update (Recommended)[/]") |
436 | | - console.print("Adding a Weco section to ~/.claude/CLAUDE.md makes Weco invocation more reliable.") |
437 | | - if Confirm.ask("Would you like to update ~/.claude/CLAUDE.md?", default=True): |
438 | | - upsert_weco_section(CLAUDE_MD_PATH, section) |
439 | | - console.print(f"[green]Weco section {action} in ~/.claude/CLAUDE.md.[/]") |
440 | | - else: |
441 | | - console.print("[yellow]Skipping ~/.claude/CLAUDE.md update.[/]") |
442 | | - console.print(f"[dim]You can manually add the Weco section to {CLAUDE_MD_PATH}[/]") |
443 | | - |
444 | 359 | console.print("\n[bold green]Setup complete![/]") |
445 | 360 | if local_path: |
446 | 361 | console.print(f"[dim]Skill copied from: {local_path}[/]") |
447 | 362 | console.print(f"[dim]Skill installed at: {WECO_SKILL_DIR}[/]") |
448 | | - console.print(f"[dim]Global CLAUDE.md at: {CLAUDE_MD_PATH}[/]") |
449 | 363 |
|
450 | 364 |
|
451 | 365 | def setup_cursor(console: Console, local_path: pathlib.Path | None = None) -> None: |
452 | 366 | """Set up Weco rules for Cursor.""" |
453 | 367 | console.print("[bold blue]Setting up Weco for Cursor...[/]\n") |
454 | 368 |
|
455 | | - # Cursor setup is intentionally "editor-config-centric": |
456 | | - # - Install/copy the skill into Cursor's skills directory (so we can read snippets). |
457 | | - # - The behavior change is controlled by `~/.cursor/rules/weco.mdc`, which is *global* |
458 | | - # editor state (not part of the installed skill folder). |
459 | | - # - Because users may have customized that file, we: |
460 | | - # 1) compute desired content from the snippet |
461 | | - # 2) check if it is already up to date |
462 | | - # 3) prompt before creating/updating it |
463 | 369 | install_skill(CURSOR_WECO_SKILL_DIR, console, local_path) |
464 | 370 |
|
465 | | - snippet_content = read_from_path(CURSOR_RULES_SNIPPET_PATH) |
466 | | - mdc_content = generate_cursor_mdc_content(snippet_content.strip()) |
467 | | - |
468 | | - # Check if already up to date |
469 | | - existing_content = None |
470 | | - if CURSOR_WECO_RULES_PATH.exists(): |
471 | | - try: |
472 | | - existing_content = read_from_path(CURSOR_WECO_RULES_PATH) |
473 | | - except Exception: |
474 | | - pass |
475 | | - |
476 | | - if existing_content is not None and existing_content.strip() == mdc_content.strip(): |
477 | | - console.print("[dim]weco.mdc already contains the latest Weco rules.[/]") |
478 | | - console.print("\n[bold green]Setup complete![/]") |
479 | | - console.print(f"[dim]Rules file at: {CURSOR_WECO_RULES_PATH}[/]") |
480 | | - return |
481 | | - |
482 | | - # Prompt user for creation/update |
483 | | - if existing_content is not None: |
484 | | - console.print("\n[bold yellow]weco.mdc Update[/]") |
485 | | - console.print("The Weco rules file can be updated to the latest version.") |
486 | | - if not Confirm.ask("Would you like to update weco.mdc?", default=True): |
487 | | - console.print("\n[yellow]Skipping weco.mdc update.[/]") |
488 | | - console.print(f"[dim]Skill installed but rules not configured. Create manually at {CURSOR_WECO_RULES_PATH}[/]") |
489 | | - return |
490 | | - else: |
491 | | - console.print("\n[bold yellow]weco.mdc Creation[/]") |
492 | | - console.print("To enable Weco optimization rules, we can create a weco.mdc file.") |
493 | | - if not Confirm.ask("Would you like to create weco.mdc?", default=True): |
494 | | - console.print("\n[yellow]Skipping weco.mdc creation.[/]") |
495 | | - console.print(f"[dim]Skill installed but rules not configured. Create manually at {CURSOR_WECO_RULES_PATH}[/]") |
496 | | - return |
497 | | - |
498 | | - write_to_path(CURSOR_WECO_RULES_PATH, mdc_content, mkdir=True) |
499 | | - console.print("[green]weco.mdc created successfully.[/]") |
500 | | - |
501 | 371 | console.print("\n[bold green]Setup complete![/]") |
502 | 372 | if local_path: |
503 | 373 | console.print(f"[dim]Skill copied from: {local_path}[/]") |
504 | 374 | console.print(f"[dim]Skill installed at: {CURSOR_WECO_SKILL_DIR}[/]") |
505 | | - console.print(f"[dim]Rules file at: {CURSOR_WECO_RULES_PATH}[/]") |
506 | 375 |
|
507 | 376 |
|
508 | 377 | # ============================================================================= |
|
0 commit comments