@@ -39,9 +39,8 @@ def _get_console(): # --> Console # noqa: F821 ANN202
39
39
@functools .lru_cache (maxsize = 1 )
40
40
def _get_console_stderr (): # --> Console # noqa: F821 ANN202
41
41
"""Lazy load rich stderr console."""
42
- import questionary # Needed for theme
43
42
from rich .console import Console
44
- console_stderr = Console (stderr = True , theme = questionary . themes . THEME )
43
+ console_stderr = Console (stderr = True )
45
44
return console_stderr
46
45
47
46
@@ -88,24 +87,42 @@ def _create_symlink(rule_name: str, source_dir: Path, dest_dir: Path) -> bool:
88
87
89
88
90
89
@app .command ("link" )
91
- def link_rules () -> None :
90
+ def link_rules () -> None : # noqa: C901 PLR0912
92
91
"""Interactively select and symlink rules from ~/.cursor/rules/ to the current directory."""
93
92
# Import required libraries here
94
93
import questionary
95
94
96
95
console = _get_console ()
97
96
console_stderr = _get_console_stderr ()
98
97
98
+ target_link_dir = TARGET_DIR / ".cursor" / "rules" # Define specific target subdir
99
+
99
100
console .print ("[bold cyan]Link Cursor Rules[/]" )
100
101
console .print (f"Source directory: [dim]{ RULES_SOURCE_DIR } [/]" )
101
- console .print (f"Target directory: [dim]{ TARGET_DIR } [/]" )
102
+ console .print (f"Target link directory: [dim]{ target_link_dir } [/]" )
102
103
104
+ # Ensure source directory exists, create if not
103
105
if not RULES_SOURCE_DIR .is_dir ():
106
+ console .print (f"[info]Source directory { RULES_SOURCE_DIR } not found. Creating it...[/]" )
107
+ try :
108
+ RULES_SOURCE_DIR .mkdir (parents = True , exist_ok = True )
109
+ console .print (f"[success]Created directory: { RULES_SOURCE_DIR } [/]" )
110
+ except OSError as e :
111
+ console_stderr .print (
112
+ f"[bold red]Error:[/] Could not create source directory { RULES_SOURCE_DIR } : { e } "
113
+ )
114
+ raise typer .Exit (code = 1 ) from e
115
+
116
+ # Ensure target link directory exists, create if not
117
+ try :
118
+ target_link_dir .mkdir (parents = True , exist_ok = True )
119
+ except OSError as e :
104
120
console_stderr .print (
105
- f"[bold red]Error:[/] Rules source directory not found : { RULES_SOURCE_DIR } "
121
+ f"[bold red]Error:[/] Could not create target link directory { target_link_dir } : { e } "
106
122
)
107
- raise typer .Exit (code = 1 )
123
+ raise typer .Exit (code = 1 ) from e
108
124
125
+ # List available rules (logic remains the same)
109
126
try :
110
127
available_rules = sorted ([item .name for item in RULES_SOURCE_DIR .iterdir ()])
111
128
except OSError as e :
@@ -120,14 +137,15 @@ def link_rules() -> None:
120
137
)
121
138
raise typer .Exit ()
122
139
140
+ # Select rules (logic remains the same)
123
141
try :
124
142
selected_rules = questionary .checkbox (
125
143
"Select rules to link to the current directory:" ,
126
144
choices = available_rules ,
127
- qmark = b "?" , # Explicitly encode qmark
145
+ qmark = "?" , # Changed back to string
128
146
).ask ()
129
147
except UnicodeDecodeError :
130
- # Fallback if encoding fails (e.g., terminal issue)
148
+ # Fallback should also use string
131
149
selected_rules = questionary .checkbox (
132
150
"Select rules to link to the current directory:" ,
133
151
choices = available_rules ,
@@ -144,20 +162,20 @@ def link_rules() -> None:
144
162
console .print ("[yellow]No rules selected. Exiting.[/]" )
145
163
raise typer .Exit ()
146
164
147
- console .print (f"\n Attempting to link { len (selected_rules )} selected rules:" )
165
+ console .print (f"\n Attempting to link { len (selected_rules )} selected rules to { target_link_dir } :" )
148
166
success_count = 0
149
167
error_count = 0
150
168
169
+ # Link selected rules to the target subdir
151
170
for rule_name in selected_rules :
152
- if _create_symlink (rule_name , RULES_SOURCE_DIR , TARGET_DIR ):
171
+ if _create_symlink (rule_name , RULES_SOURCE_DIR , target_link_dir ):
153
172
success_count += 1
154
173
else :
155
- # Note: _create_symlink prints specific errors/skips
156
- # We only count actual errors here, not skips
157
- dest_path = TARGET_DIR / rule_name
174
+ dest_path = target_link_dir / rule_name # Check against correct target
158
175
if not (dest_path .exists () or dest_path .is_symlink ()):
159
176
error_count += 1
160
177
178
+ # Summary (remains the same conceptually)
161
179
console .print ("\n [bold cyan]Link Summary:[/]" )
162
180
console .print (f" Successfully linked: [green]{ success_count } [/]" )
163
181
# Skipped count is implicitly len(selected_rules) - success_count - error_count
@@ -239,11 +257,13 @@ def add_rule( # noqa: C901 PLR0912
239
257
240
258
# 4. Ask to create symlink in current directory
241
259
if copy_success or not should_copy : # Ask even if copy was skipped but file exists
242
- if dest_rule_path .exists (): # Ensure source exists before asking to link
260
+ if dest_rule_path .exists (): # Ensure source rule exists before asking to link
243
261
console .print ("" ) # Spacer
262
+ target_link_dir = TARGET_DIR / ".cursor" / "rules" # Define specific target subdir
244
263
try :
264
+ # Updated confirmation message
245
265
create_link = questionary .confirm (
246
- f"Create a symlink for '{ rule_name } ' in the current directory ( { TARGET_DIR } )?" ,
266
+ f"Create a symlink for '{ rule_name } ' in ./.cursor/rules/ ( { target_link_dir } )?" ,
247
267
default = True ,
248
268
).ask ()
249
269
except KeyboardInterrupt :
@@ -254,11 +274,22 @@ def add_rule( # noqa: C901 PLR0912
254
274
raise typer .Exit (code = 1 ) from e
255
275
256
276
if create_link :
257
- console .print (f"Attempting to link '{ rule_name } ' to { TARGET_DIR } ..." )
258
- if not _create_symlink (rule_name , RULES_SOURCE_DIR , TARGET_DIR ):
259
- # Error/skip message printed by helper
260
- console .print ("[yellow]Symlink creation skipped or failed.[/]" )
261
- # Don't exit with error if only linking failed after successful add/confirmation
277
+ # Ensure target link directory exists, create if not
278
+ try :
279
+ target_link_dir .mkdir (parents = True , exist_ok = True )
280
+ except OSError as e :
281
+ console_stderr .print (
282
+ f"[bold red]Error:[/] Could not create target link directory { target_link_dir } : { e } "
283
+ )
284
+ # Don't exit, just report error and skip linking
285
+ console .print ("[yellow]Symlink creation skipped due to directory error.[/]" )
286
+ else :
287
+ # Attempt to link to the target subdir
288
+ console .print (f"Attempting to link '{ rule_name } ' to { target_link_dir } ..." )
289
+ if not _create_symlink (rule_name , RULES_SOURCE_DIR , target_link_dir ):
290
+ # Error/skip message printed by helper
291
+ console .print ("[yellow]Symlink creation skipped or failed.[/]" )
292
+ # Don't exit with error if only linking failed after successful add/confirmation
262
293
else :
263
294
console .print ("[info]Skipping symlink creation.[/]" )
264
295
else :
@@ -269,7 +300,7 @@ def add_rule( # noqa: C901 PLR0912
269
300
270
301
271
302
@app .command ("edit" )
272
- def edit_rule () -> None :
303
+ def edit_rule () -> None : # noqa: C901 PLR0912
273
304
"""Select a rule from ~/.cursor/rules/ and open it for editing."""
274
305
# Import required libraries here
275
306
import questionary
@@ -280,11 +311,18 @@ def edit_rule() -> None:
280
311
console .print ("[bold cyan]Edit Cursor Rule[/]" )
281
312
console .print (f"Rule directory: [dim]{ RULES_SOURCE_DIR } [/]" )
282
313
314
+ # Ensure source directory exists, create if not
283
315
if not RULES_SOURCE_DIR .is_dir ():
284
- console_stderr .print (
285
- f"[bold red]Error:[/] Rules source directory not found: { RULES_SOURCE_DIR } "
286
- )
287
- raise typer .Exit (code = 1 )
316
+ console .print (f"[info]Source directory { RULES_SOURCE_DIR } not found. Creating it...[/]" )
317
+ try :
318
+ RULES_SOURCE_DIR .mkdir (parents = True , exist_ok = True )
319
+ console .print (f"[success]Created directory: { RULES_SOURCE_DIR } [/]" )
320
+ except OSError as e :
321
+ console_stderr .print (
322
+ f"[bold red]Error:[/] Could not create source directory { RULES_SOURCE_DIR } : { e } "
323
+ )
324
+ raise typer .Exit (code = 1 ) from e
325
+ # Proceed even if directory was just created (it will be empty)
288
326
289
327
try :
290
328
available_rules = sorted (
@@ -306,10 +344,10 @@ def edit_rule() -> None:
306
344
rule_to_edit = questionary .select (
307
345
"Select a rule file to edit:" ,
308
346
choices = available_rules ,
309
- qmark = b "?" , # Explicitly encode qmark
347
+ qmark = "?" , # Changed back to string
310
348
).ask ()
311
349
except UnicodeDecodeError :
312
- # Fallback if encoding fails
350
+ # Fallback should also use string
313
351
rule_to_edit = questionary .select (
314
352
"Select a rule file to edit:" ,
315
353
choices = available_rules ,
0 commit comments