llm-ide-rules 0.3.0__tar.gz → 0.4.0__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.
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/PKG-INFO +25 -1
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/README.md +24 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/pyproject.toml +1 -1
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/__init__.py +3 -1
- llm_ide_rules-0.4.0/src/llm_ide_rules/commands/delete.py +179 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/__main__.py +0 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/commands/download.py +0 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/commands/explode.py +0 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/commands/implode.py +0 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/constants.py +0 -0
- {llm_ide_rules-0.3.0 → llm_ide_rules-0.4.0}/src/llm_ide_rules/sections.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: llm-ide-rules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: CLI tool for managing LLM IDE prompts and rules
|
|
5
5
|
Keywords: llm,ide,prompts,cursor,copilot
|
|
6
6
|
Author: Michael Bianco
|
|
@@ -62,6 +62,10 @@ uvx llm-ide-rules download [instruction_types] # Download everything by defau
|
|
|
62
62
|
uvx llm-ide-rules download cursor github # Download specific types
|
|
63
63
|
uvx llm-ide-rules download --repo other/repo # Download from different repo
|
|
64
64
|
|
|
65
|
+
# Delete downloaded instruction files
|
|
66
|
+
uvx llm-ide-rules delete [instruction_types] # Delete everything by default
|
|
67
|
+
uvx llm-ide-rules delete cursor gemini # Delete specific types
|
|
68
|
+
uvx llm-ide-rules delete --yes # Skip confirmation prompt
|
|
65
69
|
|
|
66
70
|
```
|
|
67
71
|
|
|
@@ -85,8 +89,28 @@ uvx llm-ide-rules download cursor github
|
|
|
85
89
|
|
|
86
90
|
# Download from a different repository
|
|
87
91
|
uvx llm-ide-rules download --repo other-user/other-repo --target ./my-project
|
|
92
|
+
|
|
93
|
+
# Delete all downloaded files (with confirmation)
|
|
94
|
+
uvx llm-ide-rules delete
|
|
95
|
+
|
|
96
|
+
# Delete specific instruction types
|
|
97
|
+
uvx llm-ide-rules delete cursor gemini --target ./my-project
|
|
98
|
+
|
|
99
|
+
# Delete without confirmation prompt
|
|
100
|
+
uvx llm-ide-rules delete --yes
|
|
88
101
|
```
|
|
89
102
|
|
|
103
|
+
### IDE Command Format Comparison
|
|
104
|
+
|
|
105
|
+
Different AI coding assistants use different formats for commands:
|
|
106
|
+
|
|
107
|
+
| IDE | Directory | Format | Notes |
|
|
108
|
+
|-----|-----------|--------|-------|
|
|
109
|
+
| **Cursor** | `.cursor/commands/` | `.md` (plain markdown) | Simple, no frontmatter |
|
|
110
|
+
| **Claude Code** | `.claude/commands/` | `.md` (plain markdown) | Simple, no frontmatter |
|
|
111
|
+
| **GitHub Copilot** | `.github/prompts/` | `.prompt.md` (YAML + markdown) | Requires frontmatter with `mode: 'agent'` |
|
|
112
|
+
| **Gemini CLI** | `.gemini/commands/` | `.toml` | Uses TOML format, supports `{{args}}` and shell commands |
|
|
113
|
+
|
|
90
114
|
## Development
|
|
91
115
|
|
|
92
116
|
### Using the CLI for Development
|
|
@@ -48,6 +48,10 @@ uvx llm-ide-rules download [instruction_types] # Download everything by defau
|
|
|
48
48
|
uvx llm-ide-rules download cursor github # Download specific types
|
|
49
49
|
uvx llm-ide-rules download --repo other/repo # Download from different repo
|
|
50
50
|
|
|
51
|
+
# Delete downloaded instruction files
|
|
52
|
+
uvx llm-ide-rules delete [instruction_types] # Delete everything by default
|
|
53
|
+
uvx llm-ide-rules delete cursor gemini # Delete specific types
|
|
54
|
+
uvx llm-ide-rules delete --yes # Skip confirmation prompt
|
|
51
55
|
|
|
52
56
|
```
|
|
53
57
|
|
|
@@ -71,8 +75,28 @@ uvx llm-ide-rules download cursor github
|
|
|
71
75
|
|
|
72
76
|
# Download from a different repository
|
|
73
77
|
uvx llm-ide-rules download --repo other-user/other-repo --target ./my-project
|
|
78
|
+
|
|
79
|
+
# Delete all downloaded files (with confirmation)
|
|
80
|
+
uvx llm-ide-rules delete
|
|
81
|
+
|
|
82
|
+
# Delete specific instruction types
|
|
83
|
+
uvx llm-ide-rules delete cursor gemini --target ./my-project
|
|
84
|
+
|
|
85
|
+
# Delete without confirmation prompt
|
|
86
|
+
uvx llm-ide-rules delete --yes
|
|
74
87
|
```
|
|
75
88
|
|
|
89
|
+
### IDE Command Format Comparison
|
|
90
|
+
|
|
91
|
+
Different AI coding assistants use different formats for commands:
|
|
92
|
+
|
|
93
|
+
| IDE | Directory | Format | Notes |
|
|
94
|
+
|-----|-----------|--------|-------|
|
|
95
|
+
| **Cursor** | `.cursor/commands/` | `.md` (plain markdown) | Simple, no frontmatter |
|
|
96
|
+
| **Claude Code** | `.claude/commands/` | `.md` (plain markdown) | Simple, no frontmatter |
|
|
97
|
+
| **GitHub Copilot** | `.github/prompts/` | `.prompt.md` (YAML + markdown) | Requires frontmatter with `mode: 'agent'` |
|
|
98
|
+
| **Gemini CLI** | `.gemini/commands/` | `.toml` | Uses TOML format, supports `{{args}}` and shell commands |
|
|
99
|
+
|
|
76
100
|
## Development
|
|
77
101
|
|
|
78
102
|
### Using the CLI for Development
|
|
@@ -6,8 +6,9 @@ from typing_extensions import Annotated
|
|
|
6
6
|
from llm_ide_rules.commands.explode import explode_main
|
|
7
7
|
from llm_ide_rules.commands.implode import cursor, github
|
|
8
8
|
from llm_ide_rules.commands.download import download_main
|
|
9
|
+
from llm_ide_rules.commands.delete import delete_main
|
|
9
10
|
|
|
10
|
-
__version__ = "0.
|
|
11
|
+
__version__ = "0.4.0"
|
|
11
12
|
|
|
12
13
|
app = typer.Typer(
|
|
13
14
|
name="llm_ide_rules",
|
|
@@ -18,6 +19,7 @@ app = typer.Typer(
|
|
|
18
19
|
# Add commands directly
|
|
19
20
|
app.command("explode", help="Convert instruction file to separate rule files")(explode_main)
|
|
20
21
|
app.command("download", help="Download LLM instruction files from GitHub repositories")(download_main)
|
|
22
|
+
app.command("delete", help="Remove downloaded LLM instruction files")(delete_main)
|
|
21
23
|
|
|
22
24
|
# Create implode sub-typer
|
|
23
25
|
implode_app = typer.Typer(help="Bundle rule files into a single instruction file")
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Delete command: Remove downloaded LLM instruction files."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
import structlog
|
|
9
|
+
import typer
|
|
10
|
+
from typing_extensions import Annotated
|
|
11
|
+
|
|
12
|
+
from llm_ide_rules.commands.download import INSTRUCTION_TYPES, DEFAULT_TYPES
|
|
13
|
+
|
|
14
|
+
logger = structlog.get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def find_files_to_delete(
|
|
18
|
+
instruction_types: List[str], target_dir: Path
|
|
19
|
+
) -> tuple[List[Path], List[Path]]:
|
|
20
|
+
"""Find all files and directories that would be deleted.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple of (directories, files) to delete
|
|
24
|
+
"""
|
|
25
|
+
dirs_to_delete = []
|
|
26
|
+
files_to_delete = []
|
|
27
|
+
|
|
28
|
+
for inst_type in instruction_types:
|
|
29
|
+
if inst_type not in INSTRUCTION_TYPES:
|
|
30
|
+
logger.warning("Unknown instruction type", type=inst_type)
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
config = INSTRUCTION_TYPES[inst_type]
|
|
34
|
+
|
|
35
|
+
for dir_name in config["directories"]:
|
|
36
|
+
dir_path = target_dir / dir_name
|
|
37
|
+
if dir_path.exists() and dir_path.is_dir():
|
|
38
|
+
dirs_to_delete.append(dir_path)
|
|
39
|
+
|
|
40
|
+
for file_name in config["files"]:
|
|
41
|
+
file_path = target_dir / file_name
|
|
42
|
+
if file_path.exists() and file_path.is_file():
|
|
43
|
+
files_to_delete.append(file_path)
|
|
44
|
+
|
|
45
|
+
for file_pattern in config.get("recursive_files", []):
|
|
46
|
+
matching_files = list(target_dir.rglob(file_pattern))
|
|
47
|
+
files_to_delete.extend([f for f in matching_files if f.is_file()])
|
|
48
|
+
|
|
49
|
+
return dirs_to_delete, files_to_delete
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def delete_main(
|
|
53
|
+
instruction_types: Annotated[
|
|
54
|
+
List[str],
|
|
55
|
+
typer.Argument(
|
|
56
|
+
help="Types of instructions to delete (cursor, github, gemini, claude, agent, agents). Deletes everything by default."
|
|
57
|
+
),
|
|
58
|
+
] = None,
|
|
59
|
+
target_dir: Annotated[
|
|
60
|
+
str, typer.Option("--target", "-t", help="Target directory to delete from")
|
|
61
|
+
] = ".",
|
|
62
|
+
yes: Annotated[
|
|
63
|
+
bool,
|
|
64
|
+
typer.Option("--yes", "-y", help="Skip confirmation prompt and delete immediately"),
|
|
65
|
+
] = False,
|
|
66
|
+
verbose: Annotated[
|
|
67
|
+
bool, typer.Option("--verbose", "-v", help="Enable verbose logging")
|
|
68
|
+
] = False,
|
|
69
|
+
):
|
|
70
|
+
"""Remove downloaded LLM instruction files.
|
|
71
|
+
|
|
72
|
+
This command removes files and directories that were downloaded by the 'download' command.
|
|
73
|
+
It will show you what will be deleted and ask for confirmation before proceeding.
|
|
74
|
+
|
|
75
|
+
Examples:
|
|
76
|
+
|
|
77
|
+
\b
|
|
78
|
+
# Delete everything (with confirmation)
|
|
79
|
+
llm_ide_rules delete
|
|
80
|
+
|
|
81
|
+
\b
|
|
82
|
+
# Delete only Cursor and Gemini files
|
|
83
|
+
llm_ide_rules delete cursor gemini
|
|
84
|
+
|
|
85
|
+
\b
|
|
86
|
+
# Delete without confirmation prompt
|
|
87
|
+
llm_ide_rules delete --yes
|
|
88
|
+
|
|
89
|
+
\b
|
|
90
|
+
# Delete from a specific directory
|
|
91
|
+
llm_ide_rules delete --target ./my-project
|
|
92
|
+
"""
|
|
93
|
+
if verbose:
|
|
94
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
95
|
+
structlog.configure(
|
|
96
|
+
wrapper_class=structlog.make_filtering_bound_logger(logging.DEBUG),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if not instruction_types:
|
|
100
|
+
instruction_types = DEFAULT_TYPES
|
|
101
|
+
|
|
102
|
+
invalid_types = [t for t in instruction_types if t not in INSTRUCTION_TYPES]
|
|
103
|
+
if invalid_types:
|
|
104
|
+
logger.error(
|
|
105
|
+
"Invalid instruction types",
|
|
106
|
+
invalid_types=invalid_types,
|
|
107
|
+
valid_types=list(INSTRUCTION_TYPES.keys()),
|
|
108
|
+
)
|
|
109
|
+
raise typer.Exit(1)
|
|
110
|
+
|
|
111
|
+
target_path = Path(target_dir).resolve()
|
|
112
|
+
|
|
113
|
+
if not target_path.exists():
|
|
114
|
+
logger.error("Target directory does not exist", target_dir=str(target_path))
|
|
115
|
+
typer.echo(f"Error: Target directory does not exist: {target_path}")
|
|
116
|
+
raise typer.Exit(1)
|
|
117
|
+
|
|
118
|
+
logger.info(
|
|
119
|
+
"Finding files to delete",
|
|
120
|
+
instruction_types=instruction_types,
|
|
121
|
+
target_dir=str(target_path),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
dirs_to_delete, files_to_delete = find_files_to_delete(
|
|
125
|
+
instruction_types, target_path
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if not dirs_to_delete and not files_to_delete:
|
|
129
|
+
logger.info("No files found to delete")
|
|
130
|
+
typer.echo("No matching instruction files found to delete.")
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
typer.echo("\nThe following files and directories will be deleted:\n")
|
|
134
|
+
|
|
135
|
+
if dirs_to_delete:
|
|
136
|
+
typer.echo("Directories:")
|
|
137
|
+
for dir_path in sorted(dirs_to_delete):
|
|
138
|
+
relative_path = dir_path.relative_to(target_path)
|
|
139
|
+
typer.echo(f" - {relative_path}/")
|
|
140
|
+
|
|
141
|
+
if files_to_delete:
|
|
142
|
+
typer.echo("\nFiles:")
|
|
143
|
+
for file_path in sorted(files_to_delete):
|
|
144
|
+
relative_path = file_path.relative_to(target_path)
|
|
145
|
+
typer.echo(f" - {relative_path}")
|
|
146
|
+
|
|
147
|
+
total_items = len(dirs_to_delete) + len(files_to_delete)
|
|
148
|
+
typer.echo(f"\nTotal: {total_items} items")
|
|
149
|
+
|
|
150
|
+
if not yes:
|
|
151
|
+
typer.echo()
|
|
152
|
+
confirm = typer.confirm("Are you sure you want to delete these files?")
|
|
153
|
+
if not confirm:
|
|
154
|
+
logger.info("Deletion cancelled by user")
|
|
155
|
+
typer.echo("Deletion cancelled.")
|
|
156
|
+
raise typer.Exit(0)
|
|
157
|
+
|
|
158
|
+
deleted_count = 0
|
|
159
|
+
|
|
160
|
+
for dir_path in dirs_to_delete:
|
|
161
|
+
try:
|
|
162
|
+
logger.info("Deleting directory", path=str(dir_path))
|
|
163
|
+
shutil.rmtree(dir_path)
|
|
164
|
+
deleted_count += 1
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.error("Failed to delete directory", path=str(dir_path), error=str(e))
|
|
167
|
+
typer.echo(f"Error deleting {dir_path}: {e}", err=True)
|
|
168
|
+
|
|
169
|
+
for file_path in files_to_delete:
|
|
170
|
+
try:
|
|
171
|
+
logger.info("Deleting file", path=str(file_path))
|
|
172
|
+
file_path.unlink()
|
|
173
|
+
deleted_count += 1
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error("Failed to delete file", path=str(file_path), error=str(e))
|
|
176
|
+
typer.echo(f"Error deleting {file_path}: {e}", err=True)
|
|
177
|
+
|
|
178
|
+
logger.info("Deletion completed", deleted_count=deleted_count, total_items=total_items)
|
|
179
|
+
typer.echo(f"\nSuccessfully deleted {deleted_count} of {total_items} items.")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|